Experimental approach to cancelling unnecessary promises
If a view or other resources are destroyed while a promise is being resolved, subsequent code can fail. This is generally harmless, but it results in unnecessary errors being logged to the console. To address this, promises can use a new function, Zotero.Promise.check(), to test whether a value is truthy or 0 and automatically throw a specific error that's ignored by the unhandled rejection handler if not. Example usage: getAsync().tap(() => Zotero.Promise.check(this.win)); If this.win is cleaned up while getAsync() is being resolved, subsequent lines won't be run, and nothing will be logged to the console.
This commit is contained in:
parent
3fc09add3a
commit
6b87c641d9
3 changed files with 44 additions and 10 deletions
|
@ -142,7 +142,8 @@
|
|||
Zotero.spawn(function* () {
|
||||
Zotero.debug('Refreshing attachment box');
|
||||
|
||||
yield Zotero.Promise.all([this.item.loadItemData(), this.item.loadNote()]);
|
||||
yield Zotero.Promise.all([this.item.loadItemData(), this.item.loadNote()])
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
|
||||
var attachmentBox = document.getAnonymousNodes(this)[0];
|
||||
var title = this._id('title');
|
||||
|
@ -254,7 +255,8 @@
|
|||
|
||||
// Page count
|
||||
if (this.displayPages) {
|
||||
var pages = yield Zotero.Fulltext.getPages(this.item.id);
|
||||
var pages = yield Zotero.Fulltext.getPages(this.item.id)
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
var pages = pages ? pages.total : null;
|
||||
if (pages) {
|
||||
this._id("pages-label").value = Zotero.getString('itemFields.pages')
|
||||
|
@ -273,7 +275,8 @@
|
|||
if (this.displayDateModified) {
|
||||
this._id("dateModified-label").value = Zotero.getString('itemFields.dateModified')
|
||||
+ Zotero.getString('punctuation.colon');
|
||||
var mtime = yield this.item.attachmentModificationTime;
|
||||
var mtime = yield this.item.attachmentModificationTime
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
if (mtime) {
|
||||
this._id("dateModified").value = new Date(mtime).toLocaleString();
|
||||
}
|
||||
|
@ -292,7 +295,8 @@
|
|||
|
||||
// Full-text index information
|
||||
if (this.displayIndexed) {
|
||||
yield this.updateItemIndexedState();
|
||||
yield this.updateItemIndexedState()
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
indexStatusRow.hidden = false;
|
||||
}
|
||||
else {
|
||||
|
@ -471,7 +475,8 @@
|
|||
var indexStatus = this._id('index-status');
|
||||
var reindexButton = this._id('reindex');
|
||||
|
||||
var status = yield Zotero.Fulltext.getIndexedState(this.item);
|
||||
var status = yield Zotero.Fulltext.getIndexedState(this.item)
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
var str = 'fulltext.indexState.';
|
||||
switch (status) {
|
||||
case Zotero.Fulltext.INDEX_STATE_UNAVAILABLE:
|
||||
|
@ -495,7 +500,13 @@
|
|||
var str = Zotero.getString('pane.items.menu.reindexItem');
|
||||
reindexButton.setAttribute('tooltiptext', str);
|
||||
|
||||
if (this.editable && (yield Zotero.Fulltext.canReindex(this.item))) {
|
||||
var show = false;
|
||||
if (this.editable) {
|
||||
show = yield Zotero.Fulltext.canReindex(this.item)
|
||||
.tap(() => Zotero.Promise.check(this.item));
|
||||
}
|
||||
|
||||
if (show) {
|
||||
reindexButton.setAttribute('hidden', false);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -165,6 +165,25 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
|
|||
this.initializationPromise = this.initializationDeferred.promise;
|
||||
this.locked = true;
|
||||
|
||||
// Add a function to Zotero.Promise to check whether a value is still defined, and if not
|
||||
// to throw a specific error that's ignored by the unhandled rejection handler in
|
||||
// bluebird.js. This allows for easily cancelling promises when they're no longer
|
||||
// needed, for example after a view is destroyed.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// getAsync.tap(() => Zotero.Promise.check(this.win))
|
||||
//
|
||||
// If this.win is cleaned up while getAsync() is being resolved, subsequent lines won't
|
||||
// be run, and nothing will be logged to the console.
|
||||
this.Promise.check = function (val) {
|
||||
if (!val && val !== 0) {
|
||||
let e = new Error;
|
||||
e.name = "ZoteroPromiseInterrupt";
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
// Load in the preferences branch for the extension
|
||||
Zotero.Prefs.init();
|
||||
Zotero.Debug.init(options && options.forceDebugLog);
|
||||
|
|
|
@ -91,12 +91,16 @@
|
|||
Promise = e();
|
||||
// TEMP: Only turn on if debug logging enabled?
|
||||
Promise.longStackTraces();
|
||||
Promise.onPossiblyUnhandledRejection(function(error) {
|
||||
Promise.onPossiblyUnhandledRejection(function (e, promise) {
|
||||
if (e.name == 'ZoteroPromiseInterrupt') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore some errors during tests
|
||||
if (error.message && error.message.indexOf(' -- ignore') != -1) return;
|
||||
if (e.message && e.message.indexOf(' -- ignore') != -1) return;
|
||||
|
||||
self.debug('Unhandled rejection:\n\n' + error.stack);
|
||||
throw error;
|
||||
self.debug('Unhandled rejection:\n\n' + e.stack);
|
||||
throw e;
|
||||
});
|
||||
return;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue