Search code examples
angularobservableindexeddbngrx-effectsdexie

Dexie & Angular 4: slow performance when selecting items


I'm having issues with selecting items (between 1.000 and 4.000) via a query from my IndexedDB with Dexie in an Angular 4 application.

There are only max 20.000 items in the tables, but the selection of these takes multiple seconds (5s on Chrome 61, up to (and more) than 20s on iOS 10 & iOS 11)

Below is my service that fetches two different tables and returns an Observable via loadItems()

@Injectable()
export class ItemService {

    private buildings: Dexie.Table<Building, string>;
    private people: Dexie.Table<Person, string>;

    private activeZip: string;

    constructor(
        private db: IndexeddbService,
    ) {
        this.buildings = this.db.table('buildings');
        this.people = this.db.table('people');
    }

    loadItems(): Observable<{
        buildings: Building[],
        people: Person[]
    }> {
        return Observable.combineLatest(
            this.loadBuildings(),
            this.loadPeople(),
        ).map(([buildings, people]) => {
            return {
                buildings,
                people
            };
        });
    }

    private loadBuildings(): Observable<Building[]> {
        return Observable.from(this.buildings.where('zip').equals(this.activeZip).toArray());
    }

    private loadPeople(): Observable<Person[]> {
        return Observable.from(this.people.where('zip').equals(this.activeZip).toArray());
    }
}

The resulting Observable is asynchronously handled with a ngrx effect, which dispatches an Action that writes the data to the state, so the component can render the information.

@Effect()
loadItems$: Observable<Action> = this.actions$
    .ofType(actions.ActionTypes.LOAD_ITEMS)
    .map(_ => this.itemService.setActiveZip(this.localStorageService.getActiveZip()))
    .switchMap(_ => this.itemService.loadItems())
    .map(items => new actions.LoadItemsSuccessAction(items))
    .catch(error => Observable.of(new actions.LoadItemsFailAction(error)));

I've tried to "lazy-load" the items in chunks via https://github.com/raphinesse/dexie-batch, but the resulting batches took more than 500ms to arrive.

Where do I have a possible performance bottleneck? I've already tried to run this query outside of Angular's zones, but this did not yield and performance improvements.


Solution

  • With a lot of time and debugging, I've identified the following Dexie PR which breaks the IndexedDB 2.0 getAll feature in Chrome and Safari: https://github.com/dfahlander/Dexie.js/pull/579

    With a revert back to Dexie 2.0.0-beta.11 performance is increased around 10x times (raw database queries via cursor to getAll went from 600-700ms back to 60ms)

    Edit: Dexie 2.0.1 has been released with a correct fix for this issue