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
|
@ -142,7 +142,8 @@
|
||||||
Zotero.spawn(function* () {
|
Zotero.spawn(function* () {
|
||||||
Zotero.debug('Refreshing attachment box');
|
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 attachmentBox = document.getAnonymousNodes(this)[0];
|
||||||
var title = this._id('title');
|
var title = this._id('title');
|
||||||
|
@ -254,7 +255,8 @@
|
||||||
|
|
||||||
// Page count
|
// Page count
|
||||||
if (this.displayPages) {
|
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;
|
var pages = pages ? pages.total : null;
|
||||||
if (pages) {
|
if (pages) {
|
||||||
this._id("pages-label").value = Zotero.getString('itemFields.pages')
|
this._id("pages-label").value = Zotero.getString('itemFields.pages')
|
||||||
|
@ -273,7 +275,8 @@
|
||||||
if (this.displayDateModified) {
|
if (this.displayDateModified) {
|
||||||
this._id("dateModified-label").value = Zotero.getString('itemFields.dateModified')
|
this._id("dateModified-label").value = Zotero.getString('itemFields.dateModified')
|
||||||
+ Zotero.getString('punctuation.colon');
|
+ Zotero.getString('punctuation.colon');
|
||||||
var mtime = yield this.item.attachmentModificationTime;
|
var mtime = yield this.item.attachmentModificationTime
|
||||||
|
.tap(() => Zotero.Promise.check(this.item));
|
||||||
if (mtime) {
|
if (mtime) {
|
||||||
this._id("dateModified").value = new Date(mtime).toLocaleString();
|
this._id("dateModified").value = new Date(mtime).toLocaleString();
|
||||||
}
|
}
|
||||||
|
@ -292,7 +295,8 @@
|
||||||
|
|
||||||
// Full-text index information
|
// Full-text index information
|
||||||
if (this.displayIndexed) {
|
if (this.displayIndexed) {
|
||||||
yield this.updateItemIndexedState();
|
yield this.updateItemIndexedState()
|
||||||
|
.tap(() => Zotero.Promise.check(this.item));
|
||||||
indexStatusRow.hidden = false;
|
indexStatusRow.hidden = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -471,7 +475,8 @@
|
||||||
var indexStatus = this._id('index-status');
|
var indexStatus = this._id('index-status');
|
||||||
var reindexButton = this._id('reindex');
|
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.';
|
var str = 'fulltext.indexState.';
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case Zotero.Fulltext.INDEX_STATE_UNAVAILABLE:
|
case Zotero.Fulltext.INDEX_STATE_UNAVAILABLE:
|
||||||
|
@ -495,7 +500,13 @@
|
||||||
var str = Zotero.getString('pane.items.menu.reindexItem');
|
var str = Zotero.getString('pane.items.menu.reindexItem');
|
||||||
reindexButton.setAttribute('tooltiptext', str);
|
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);
|
reindexButton.setAttribute('hidden', false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -165,6 +165,25 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||||
this.initializationPromise = this.initializationDeferred.promise;
|
this.initializationPromise = this.initializationDeferred.promise;
|
||||||
this.locked = true;
|
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
|
// Load in the preferences branch for the extension
|
||||||
Zotero.Prefs.init();
|
Zotero.Prefs.init();
|
||||||
Zotero.Debug.init(options && options.forceDebugLog);
|
Zotero.Debug.init(options && options.forceDebugLog);
|
||||||
|
|
|
@ -91,12 +91,16 @@
|
||||||
Promise = e();
|
Promise = e();
|
||||||
// TEMP: Only turn on if debug logging enabled?
|
// TEMP: Only turn on if debug logging enabled?
|
||||||
Promise.longStackTraces();
|
Promise.longStackTraces();
|
||||||
Promise.onPossiblyUnhandledRejection(function(error) {
|
Promise.onPossiblyUnhandledRejection(function (e, promise) {
|
||||||
|
if (e.name == 'ZoteroPromiseInterrupt') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore some errors during tests
|
// 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);
|
self.debug('Unhandled rejection:\n\n' + e.stack);
|
||||||
throw error;
|
throw e;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user