Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

By default, log to console.error if any Promise was uncaught. #206

Merged
merged 3 commits into from
Mar 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 13 additions & 20 deletions src/Dexie.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ export default function Dexie(dbName, options) {
});
});
if (autoOpen && !isBeingOpened) {
db.open();
db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise.
}
return blockedPromise;
} else {
Expand Down Expand Up @@ -484,7 +484,7 @@ export default function Dexie(dbName, options) {
if (!fake && db_is_blocked && (!Promise.PSD || !Promise.PSD.letThrough)) {
if (!isBeingOpened) {
if (autoOpen) {
db.open();
db.open().catch(nop); // catching to get rid of error logging of uncaught Promise. dbOpenError will be returned again as a rejected Promise.
} else {
return fail(new exceptions.DatabaseClosed());
}
Expand Down Expand Up @@ -789,6 +789,7 @@ export default function Dexie(dbName, options) {
function enterTransactionScope(resolve, reject) {
// Our transaction. To be set later.
var trans = null;
var isConstructing = true;

try {
// Throw any error if any of the above checks failed.
Expand Down Expand Up @@ -861,9 +862,13 @@ export default function Dexie(dbName, options) {
parentTransaction.active = false;
parentTransaction.on.error.fire(e); // Bubble to parent transaction
}
var catched = reject(e);
if (!parentTransaction && !catched) {
db.on.error.fire(e);// If not catched, bubble error to db.on("error").

if (isConstructing) asap(doReject); else doReject();
function doReject() {
var catched = reject(e);
if (!parentTransaction && !catched) {
db.on.error.fire(e);// If not catched, bubble error to db.on("error").
}
}
});

Expand All @@ -889,6 +894,7 @@ export default function Dexie(dbName, options) {
if (!reject(e)) db.on("error").fire(e); // If not catched, bubble exception to db.on("error");
});
}
isConstructing = false;
}
};

Expand Down Expand Up @@ -976,23 +982,10 @@ export default function Dexie(dbName, options) {
return this.toCollection().and(filterFunction);
},
each: function (fn) {
var self = this;
fake && fn(self.schema.instanceTemplate);
return this._idbstore(READONLY, function (resolve, reject, idbstore) {
var req = idbstore.openCursor();
req.onerror = eventRejectHandler(reject, ["calling", "Table.each()", "on", self.name]);
iterate(req, null, fn, resolve, reject, self.hook.reading.fire);
});
return this.toCollection().each(fn);
},
toArray: function (cb) {
var self = this;
return this._idbstore(READONLY, function (resolve, reject, idbstore) {
fake && resolve([self.schema.instanceTemplate]);
var a = [];
var req = idbstore.openCursor();
req.onerror = eventRejectHandler(reject, ["calling", "Table.toArray()", "on", self.name]);
iterate(req, null, function (item) { a.push(item); }, function () { resolve(a); }, reject, self.hook.reading.fire);
}).then(cb);
return this.toCollection().toArray(cb);
},
orderBy: function (index) {
return new this._collClass(new WhereClause(this, index));
Expand Down
33 changes: 21 additions & 12 deletions src/Promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,7 @@ function handle(self, deferred) {
if (!self._state && (!ret || typeof ret.then !== 'function' || ret._state !== false)) setCatched(self); // Caller did 'return Promise.reject(err);' - don't regard it as catched!
deferred.resolve(ret);
} catch (e) {
var catched = deferred.reject(e);
if (!catched && self.onuncatched) {
try {
self.onuncatched(e);
} catch (e) {
}
}
deferred.reject(e);
} finally {
Promise.PSD = outerPSD;
if (isRootExec) {
Expand Down Expand Up @@ -149,7 +143,7 @@ function _rootExec(fn) {

function setCatched(promise) {
promise._catched = true;
if (promise._parent) setCatched(promise._parent);
if (promise._parent && !promise._parent._catched) setCatched(promise._parent);
}

function resolve(promise, newValue) {
Expand All @@ -159,6 +153,12 @@ function resolve(promise, newValue) {
if (newValue === promise) throw new TypeError('A promise cannot be resolved with itself.');
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
if (typeof newValue.then === 'function') {
if (newValue instanceof Promise && newValue._state !== null) {
promise._state = newValue._state;
promise._value = newValue._value;
finale.call(promise);
return;
}
doResolve(promise, function (resolve, reject) {
//newValue instanceof Promise ? newValue._then(resolve, reject) : newValue.then(resolve, reject);
newValue.then(resolve, reject);
Expand All @@ -185,11 +185,12 @@ function reject(promise, newValue) {
promise._value = newValue;

finale.call(promise);
if (!promise._catched) {
if (!promise._catched ) {
try {
if (promise.onuncatched)
promise.onuncatched(promise._value);
Promise.on.error.fire(promise._value);
else
Promise.on.error.fire(promise._value);
} catch (e) {
}
}
Expand Down Expand Up @@ -235,8 +236,6 @@ function doResolve(promise, fn, onFulfilled, onRejected) {
}
}

Promise.on = Events(null, "error");

Promise.all = function () {
var args = slice(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);

Expand Down Expand Up @@ -355,3 +354,13 @@ Promise._tickFinalize = function(callback) {
if (isRootExecution) throw new Error("Not in a virtual tick");
tickFinalizers.push(callback);
};

Promise.on = Events(null, {"error": [
(f1,f2)=>f2, // Only use the most recent handler (only allow one handler at a time).
defaultErrorHandler] // Default to defaultErrorHandler
});

// By default, log uncaught errors to the console
function defaultErrorHandler(e) {
console.error(`Uncaught Promise: ${e.stack || e}`);
}
2 changes: 1 addition & 1 deletion test/tests-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ asyncTest("modify-causing-error", 2, function () {
asyncTest("delete", 2, function () {
db.users.orderBy("id").delete().then(function (count) {
equal(count, 2, "All two records deleted");
db.users.count(function (count) {
return db.users.count(function (count) {
equal(count, 0, "No users in collection anymore");
});
}).catch(function (e) {
Expand Down
4 changes: 4 additions & 0 deletions test/tests-exception-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,13 @@ asyncTest("catch-all with db.on('error')", 3, function () {
ourDB.on("error", function (e) {
ok(errorCount < 3, "Uncatched error successfully bubbled to ourDB.on('error'): " + e);
if (++errorCount == 3) {
Dexie.Promise.on('error').unsubscribe(swallowPromiseOnError);
ourDB.delete().then(start);
}
});
function swallowPromiseOnError(e){
}
Dexie.Promise.on('error', swallowPromiseOnError); // Just to get rid of default error logs for not catching.

ourDB.open();

Expand Down
1 change: 0 additions & 1 deletion test/tests-open.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ spawnedTest("Using db on node should be rejected with MissingAPIError", function
} catch (e) {
ok(e instanceof Dexie.MissingAPIError, "Should get MissingAPIError. Got: " + e.name);
}

});

asyncTest("open, add and query data without transaction", 6, function () {
Expand Down
Loading