Skip to content

Commit 920080a

Browse files
committed
Performance boost
1 parent 4388e19 commit 920080a

File tree

1 file changed

+50
-40
lines changed

1 file changed

+50
-40
lines changed

src/Dexie.js

+50-40
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
(function (global, publish, undefined) {
1515

1616
"use strict";
17+
18+
var isArray = Array.isArray;
19+
var keys = Object.keys;
20+
var _slice = [].slice;
1721

1822
function extend(obj, extension) {
1923
if (typeof extension !== 'object') extension = extension(); // Allow to supply a function returning the extension. Useful for simplifying private scopes.
20-
Object.keys(extension).forEach(function (key) {
24+
keys(extension).forEach(function (key) {
2125
obj[key] = extension[key];
2226
});
2327
return obj;
@@ -37,6 +41,10 @@
3741
};
3842
}
3943

44+
function slice(args, start, end) {
45+
return _slice.call(args, start, end);
46+
}
47+
4048
function override(origFunc, overridedFactory) {
4149
return overridedFactory(origFunc);
4250
}
@@ -146,22 +154,22 @@
146154
// Update API
147155
globalSchema = db._dbSchema = dbschema;
148156
removeTablesApi([allTables, db, notInTransFallbackTables]);
149-
setApiOnPlace([notInTransFallbackTables], tableNotInTransaction, Object.keys(dbschema), READWRITE, dbschema);
150-
setApiOnPlace([allTables, db, this._cfg.tables], db._transPromiseFactory, Object.keys(dbschema), READWRITE, dbschema, true);
151-
dbStoreNames = Object.keys(dbschema);
157+
setApiOnPlace([notInTransFallbackTables], tableNotInTransaction, keys(dbschema), READWRITE, dbschema);
158+
setApiOnPlace([allTables, db, this._cfg.tables], db._transPromiseFactory, keys(dbschema), READWRITE, dbschema, true);
159+
dbStoreNames = keys(dbschema);
152160
return this;
153161
},
154162
upgrade: function (upgradeFunction) {
155163
/// <param name="upgradeFunction" optional="true">Function that performs upgrading actions.</param>
156164
var self = this;
157165
fakeAutoComplete(function () {
158-
upgradeFunction(db._createTransaction(READWRITE, Object.keys(self._cfg.dbschema), self._cfg.dbschema));// BUGBUG: No code completion for prev version's tables wont appear.
166+
upgradeFunction(db._createTransaction(READWRITE, keys(self._cfg.dbschema), self._cfg.dbschema));// BUGBUG: No code completion for prev version's tables wont appear.
159167
});
160168
this._cfg.contentUpgrade = upgradeFunction;
161169
return this;
162170
},
163171
_parseStoresSpec: function (stores, outSchema) {
164-
Object.keys(stores).forEach(function (tableName) {
172+
keys(stores).forEach(function (tableName) {
165173
if (stores[tableName] !== null) {
166174
var instanceTemplate = {};
167175
var indexes = parseIndexSyntax(stores[tableName]);
@@ -183,7 +191,7 @@
183191
if (oldVersion === 0) {
184192
//globalSchema = versions[versions.length - 1]._cfg.dbschema;
185193
// Create tables:
186-
Object.keys(globalSchema).forEach(function (tableName) {
194+
keys(globalSchema).forEach(function (tableName) {
187195
createTable(idbtrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes);
188196
});
189197
// Populate data
@@ -250,7 +258,7 @@
250258
if (version._cfg.contentUpgrade) {
251259
queue.push(function (idbtrans, cb) {
252260
anyContentUpgraderHasRun = true;
253-
var t = db._createTransaction(READWRITE, [].slice.call(idbtrans.db.objectStoreNames, 0), newSchema);
261+
var t = db._createTransaction(READWRITE, slice(idbtrans.db.objectStoreNames), newSchema);
254262
t.idbtrans = idbtrans;
255263
var uncompletedRequests = 0;
256264
t._promise = override(t._promise, function (orig_promise) {
@@ -358,7 +366,7 @@
358366
}
359367

360368
function createMissingTables(newSchema, idbtrans) {
361-
Object.keys(newSchema).forEach(function (tableName) {
369+
keys(newSchema).forEach(function (tableName) {
362370
if (!idbtrans.db.objectStoreNames.contains(tableName)) {
363371
createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes);
364372
}
@@ -652,7 +660,7 @@
652660
Object.defineProperty(this, "tables", {
653661
get: function () {
654662
/// <returns type="Array" elementType="WriteableTable" />
655-
return Object.keys(allTables).map(function (name) { return allTables[name]; });
663+
return keys(allTables).map(function (name) { return allTables[name]; });
656664
}
657665
});
658666

@@ -693,7 +701,7 @@
693701
/// <param name="scopeFunc" type="Function">Function to execute with transaction</param>
694702

695703
// Let table arguments be all arguments between mode and last argument.
696-
tableInstances = [].slice.call(arguments, 1, arguments.length - 1);
704+
tableInstances = slice(arguments, 1, arguments.length - 1);
697705
// Let scopeFunc be the last argument
698706
scopeFunc = arguments[arguments.length - 1];
699707
var parentTransaction = Promise.PSD && Promise.PSD.trans;
@@ -704,7 +712,7 @@
704712
//
705713
// Get storeNames from arguments. Either through given table instances, or through given table names.
706714
//
707-
var tables = Array.isArray(tableInstances[0]) ? tableInstances.reduce(function (a, b) { return a.concat(b); }) : tableInstances;
715+
var tables = isArray(tableInstances[0]) ? tableInstances.reduce(function (a, b) { return a.concat(b); }) : tableInstances;
708716
var error = null;
709717
var storeNames = tables.map(function (tableInstance) {
710718
if (typeof tableInstance === "string") {
@@ -1154,10 +1162,10 @@
11541162
},
11551163

11561164
update: function (keyOrObject, modifications) {
1157-
if (typeof modifications !== 'object' || Array.isArray(modifications)) throw new Error("db.update(keyOrObject, modifications). modifications must be an object.");
1158-
if (typeof keyOrObject === 'object' && !Array.isArray(keyOrObject)) {
1165+
if (typeof modifications !== 'object' || isArray(modifications)) throw new Error("db.update(keyOrObject, modifications). modifications must be an object.");
1166+
if (typeof keyOrObject === 'object' && !isArray(keyOrObject)) {
11591167
// object to modify. Also modify given object with the modifications:
1160-
Object.keys(modifications).forEach(function (keyPath) {
1168+
keys(modifications).forEach(function (keyPath) {
11611169
setByKeyPath(keyOrObject, keyPath, modifications[keyPath]);
11621170
});
11631171
var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);
@@ -1374,7 +1382,7 @@
13741382
}
13751383

13761384
function getSetArgs(args) {
1377-
return Array.prototype.slice.call(args.length === 1 && Array.isArray(args[0]) ? args[0] : args);
1385+
return slice(args.length === 1 && isArray(args[0]) ? args[0] : args);
13781386
}
13791387

13801388
function upperFactory(dir) {
@@ -2000,7 +2008,7 @@
20002008
if (additionalChanges) {
20012009
// Hook want to apply additional modifications. Make sure to fullfill the will of the hook.
20022010
item = this.value;
2003-
Object.keys(additionalChanges).forEach(function (keyPath) {
2011+
keys(additionalChanges).forEach(function (keyPath) {
20042012
setByKeyPath(item, keyPath, additionalChanges[keyPath]); // Adding {keyPath: undefined} means that the keyPath should be deleted. Handled by setByKeyPath
20052013
});
20062014
}
@@ -2009,7 +2017,7 @@
20092017
}
20102018
} else if (updatingHook === nop) {
20112019
// changes is a set of {keyPath: value} and no one is listening to the updating hook.
2012-
var keyPaths = Object.keys(changes);
2020+
var keyPaths = keys(changes);
20132021
var numKeys = keyPaths.length;
20142022
modifyer = function (item) {
20152023
var anythingModified = false;
@@ -2031,7 +2039,7 @@
20312039
var anythingModified = false;
20322040
var additionalChanges = updatingHook.call(this, changes, this.primKey, deepClone(item), trans);
20332041
if (additionalChanges) extend(changes, additionalChanges);
2034-
Object.keys(changes).forEach(function (keyPath) {
2042+
keys(changes).forEach(function (keyPath) {
20352043
var val = changes[keyPath];
20362044
if (getByKeyPath(item, keyPath) !== val) {
20372045
setByKeyPath(item, keyPath, val);
@@ -2194,7 +2202,7 @@
21942202
index.indexOf('&') !== -1,
21952203
index.indexOf('*') !== -1,
21962204
index.indexOf("++") !== -1,
2197-
Array.isArray(keyPath),
2205+
isArray(keyPath),
21982206
keyPath.indexOf('.') !== -1
21992207
));
22002208
});
@@ -2234,7 +2242,7 @@
22342242
function readGlobalSchema() {
22352243
db.verno = idbdb.version / 10;
22362244
db._dbSchema = globalSchema = {};
2237-
dbStoreNames = [].slice.call(idbdb.objectStoreNames, 0);
2245+
dbStoreNames = slice(idbdb.objectStoreNames, 0);
22382246
if (dbStoreNames.length === 0) return; // Database contains no stores.
22392247
var trans = idbdb.transaction(safariMultiStoreFix(dbStoreNames), 'readonly');
22402248
dbStoreNames.forEach(function (storeName) {
@@ -2252,7 +2260,7 @@
22522260
}
22532261
globalSchema[storeName] = new TableSchema(storeName, primKey, indexes, {});
22542262
});
2255-
setApiOnPlace([allTables], db._transPromiseFactory, Object.keys(globalSchema), READWRITE, globalSchema);
2263+
setApiOnPlace([allTables], db._transPromiseFactory, keys(globalSchema), READWRITE, globalSchema);
22562264
}
22572265

22582266
function adjustToExistingIndexNames(schema, idbtrans) {
@@ -2268,7 +2276,7 @@
22682276
for (var j = 0; j < store.indexNames.length; ++j) {
22692277
var indexName = store.indexNames[j];
22702278
var keyPath = store.index(indexName).keyPath;
2271-
var dexieName = typeof keyPath === 'string' ? keyPath : "[" + [].slice.call(keyPath).join('+') + "]";
2279+
var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice(keyPath).join('+') + "]";
22722280
if (schema[storeName]) {
22732281
var indexSpec = schema[storeName].idxByName[dexieName];
22742282
if (indexSpec) indexSpec.name = indexName;
@@ -2315,16 +2323,19 @@
23152323
var Promise = (function () {
23162324

23172325
// The use of asap in handle() is remarked because we must NOT use setTimeout(fn,0) because it causes premature commit of indexedDB transactions - which is according to indexedDB specification.
2318-
var _slice = [].slice;
2319-
var _asap = typeof setImmediate === 'undefined' ? function(fn, arg1, arg2, argN) {
2320-
var args = arguments;
2321-
setTimeout(function() { fn.apply(global, _slice.call(args, 1)); }, 0); // If not FF13 and earlier failed, we could use this call here instead: setTimeout.call(this, [fn, 0].concat(arguments));
2322-
} : setImmediate; // IE10+ and node.
2326+
var _asap = global.setImmediate || function(fn) {
2327+
var args = slice(arguments, 1);
2328+
2329+
// If not FF13 and earlier failed, we could use this call here instead: setTimeout.call(this, [fn, 0].concat(arguments));
2330+
setTimeout(function() {
2331+
fn.apply(global, args);
2332+
}, 0);
2333+
}
23232334

23242335
doFakeAutoComplete(function () {
23252336
// Simplify the job for VS Intellisense. This piece of code is one of the keys to the new marvellous intellisense support in Dexie.
23262337
_asap = asap = enqueueImmediate = function(fn) {
2327-
var args = arguments; setTimeout(function() { fn.apply(global, _slice.call(args, 1)); }, 0);
2338+
var args = arguments; setTimeout(function() { fn.apply(global, slice(args, 1)); }, 0);
23282339
};
23292340
});
23302341

@@ -2334,7 +2345,7 @@
23342345
var operationsQueue = [];
23352346
var tickFinalizers = [];
23362347
function enqueueImmediate(fn, args) {
2337-
operationsQueue.push([fn, _slice.call(arguments, 1)]);
2348+
operationsQueue.push([fn, slice(arguments, 1)]);
23382349
}
23392350

23402351
function executeOperationsQueue() {
@@ -2530,7 +2541,7 @@
25302541
Promise.on = events(null, "error");
25312542

25322543
Promise.all = function () {
2533-
var args = Array.prototype.slice.call(arguments.length === 1 && Array.isArray(arguments[0]) ? arguments[0] : arguments);
2544+
var args = slice(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
25342545

25352546
return new Promise(function (resolve, reject) {
25362547
if (args.length === 0) return resolve([]);
@@ -2757,7 +2768,7 @@
27572768
var rv = function (eventName, subscriber) {
27582769
if (subscriber) {
27592770
// Subscribe
2760-
var args = [].slice.call(arguments, 1);
2771+
var args = slice(arguments, 1);
27612772
var ev = evs[eventName];
27622773
ev.subscribe.apply(ev, args);
27632774
return ctx;
@@ -2769,7 +2780,7 @@
27692780
rv.addEventType = add;
27702781

27712782
function add(eventName, chainFunction, defaultFunction) {
2772-
if (Array.isArray(eventName)) return addEventGroup(eventName);
2783+
if (isArray(eventName)) return addEventGroup(eventName);
27732784
if (typeof eventName === 'object') return addConfiguredEvents(eventName);
27742785
if (!chainFunction) chainFunction = stoppableEventChain;
27752786
if (!defaultFunction) defaultFunction = nop;
@@ -2792,9 +2803,9 @@
27922803

27932804
function addConfiguredEvents(cfg) {
27942805
// events(this, {reading: [functionChain, nop]});
2795-
Object.keys(cfg).forEach(function (eventName) {
2806+
keys(cfg).forEach(function (eventName) {
27962807
var args = cfg[eventName];
2797-
if (Array.isArray(args)) {
2808+
if (isArray(args)) {
27982809
add(eventName, cfg[eventName][0], cfg[eventName][1]);
27992810
} else if (args === 'asap') {
28002811
// Rather than approaching event subscription using a functional approach, we here do it in a for-loop where subscriber is executed in its own stack
@@ -2935,7 +2946,7 @@
29352946
function deepClone(any) {
29362947
if (!any || typeof any !== 'object') return any;
29372948
var rv;
2938-
if (Array.isArray(any)) {
2949+
if (isArray(any)) {
29392950
rv = [];
29402951
for (var i = 0, l = any.length; i < l; ++i) {
29412952
rv.push(deepClone(any[i]));
@@ -2975,7 +2986,7 @@
29752986
function parseType(type) {
29762987
if (typeof type === 'function') {
29772988
return new type();
2978-
} else if (Array.isArray(type)) {
2989+
} else if (isArray(type)) {
29792990
return [parseType(type[0])];
29802991
} else if (type && typeof type === 'object') {
29812992
var rv = {};
@@ -2987,7 +2998,7 @@
29872998
}
29882999

29893000
function applyStructure(obj, structure) {
2990-
Object.keys(structure).forEach(function (member) {
3001+
keys(structure).forEach(function (member) {
29913002
var value = parseType(structure[member]);
29923003
obj[member] = value;
29933004
});
@@ -3143,7 +3154,7 @@
31433154
if (getDatabaseNames) { // In case getDatabaseNames() becomes standard, let's prepare to support it:
31443155
var req = getDatabaseNames();
31453156
req.onsuccess = function (event) {
3146-
resolve([].slice.call(event.target.result, 0)); // Converst DOMStringList to Array<String>
3157+
resolve(slice(event.target.result, 0)); // Converst DOMStringList to Array<String>
31473158
};
31483159
req.onerror = eventRejectHandler(reject);
31493160
} else {
@@ -3302,4 +3313,3 @@
33023313

33033314
// Vanilla HTML and WebWorkers:
33043315
: [self || window, function (name, value) { (self || window)[name] = value; }]);
3305-

0 commit comments

Comments
 (0)