diff --git a/chrome/content/zotero/bindings/attachmentbox.xml b/chrome/content/zotero/bindings/attachmentbox.xml index b032eb02ae..dceb080793 100644 --- a/chrome/content/zotero/bindings/attachmentbox.xml +++ b/chrome/content/zotero/bindings/attachmentbox.xml @@ -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 { diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index 2e2112e637..8defbd6ef1 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -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); diff --git a/resource/bluebird.js b/resource/bluebird.js index 09e752872c..e8c434fef0 100644 --- a/resource/bluebird.js +++ b/resource/bluebird.js @@ -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;