1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 18:07:58 +01:00

Promises cleanup.

This commit is contained in:
Kris Maglione
2015-03-02 18:12:57 -08:00
parent c84c657d27
commit 7b2f821e04
10 changed files with 160 additions and 126 deletions

1
common/bootstrap.js vendored
View File

@@ -264,6 +264,7 @@ function init() {
bootstrap = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(), bootstrap = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(),
{ sandboxName: BOOTSTRAP, { sandboxName: BOOTSTRAP,
addonId: addon.id, addonId: addon.id,
wantGlobalProperties: ["TextDecoder", "TextEncoder"],
metadata: { addonID: addon.id } }); metadata: { addonID: addon.id } });
Services.scriptloader.loadSubScript(BOOTSTRAP, bootstrap); Services.scriptloader.loadSubScript(BOOTSTRAP, bootstrap);
} }

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org> // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com> // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2014 Kris Maglione <maglione.k@gmail.com> // Copyright (c) 2008-2015 Kris Maglione <maglione.k@gmail.com>
// //
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
@@ -302,23 +302,22 @@ var Bookmarks = Module("bookmarks", {
* @returns {Promise<Array>} * @returns {Promise<Array>}
*/ */
makeSuggestions: function makeSuggestions(url, parser) { makeSuggestions: function makeSuggestions(url, parser) {
let deferred = Promise.defer(); return new CancelablePromise((resolve, reject, canceled) => {
let req = util.fetchUrl(url);
req.then(function process(req) {
let results = [];
try {
results = parser(req);
}
catch (e) {
reject(e);
return;
}
resolve(results);
});
let req = util.fetchUrl(url); canceled.then(req.cancel);
req.then(function process(req) {
let results = [];
try {
results = parser(req);
}
catch (e) {
deferred.reject(e);
return;
}
deferred.resolve(results);
}); });
promises.oncancel(deferred, reason => promises.cancel(req, reason));
return deferred.promise;
}, },
suggestionProviders: {}, suggestionProviders: {},

View File

@@ -855,13 +855,15 @@ var CommandLine = Module("commandline", {
* @... {string} default - The initial value that will be returned * @... {string} default - The initial value that will be returned
* if the user presses <CR> straightaway. @default "" * if the user presses <CR> straightaway. @default ""
*/ */
input: promises.withCallbacks(function _input([callback, reject], prompt, extra={}, thing={}) { input: function _input(prompt, extra={}, thing={}) {
if (callable(extra)) return new Promise((resolve, reject) => {
// Deprecated. if (callable(extra))
[callback, extra] = [extra, thing]; // Deprecated.
[resolve, extra] = [extra, thing];
CommandPromptMode(prompt, update({ onSubmit: callback, onCancel: reject }, extra)).open(); CommandPromptMode(prompt, update({ onSubmit: resolve, onCancel: reject }, extra)).open();
}), });
},
readHeredoc: function readHeredoc(end) { readHeredoc: function readHeredoc(end) {
return util.waitFor(commandline.inputMultiline(end)); return util.waitFor(commandline.inputMultiline(end));
@@ -876,33 +878,35 @@ var CommandLine = Module("commandline", {
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
// FIXME: Buggy, especially when pasting. // FIXME: Buggy, especially when pasting.
inputMultiline: promises.withCallbacks(function inputMultiline([callback], end) { inputMultiline: function inputMultiline(end) {
let cmd = this.command; return new Promise((resolve, reject) => {
let self = { let cmd = this.command;
end: "\n" + end + "\n", let self = {
callback: callback end: "\n" + end + "\n",
}; callback: resolve
};
modes.push(modes.INPUT_MULTILINE, null, { modes.push(modes.INPUT_MULTILINE, null, {
holdFocus: true, holdFocus: true,
leave: function leave() { leave: function leave() {
if (!self.done) if (!self.done)
self.callback(null); self.callback(null);
}, },
mappingSelf: self mappingSelf: self
});
if (cmd != false)
this._echoLine(cmd, this.HL_NORMAL);
// save the arguments, they are needed in the event handler onKeyPress
this.multilineInputVisible = true;
this.widgets.multilineInput.value = "";
this._autosizeMultilineInputWidget();
this.timeout(function () { dactyl.focus(this.widgets.multilineInput); }, 10);
}); });
},
if (cmd != false)
this._echoLine(cmd, this.HL_NORMAL);
// save the arguments, they are needed in the event handler onKeyPress
this.multilineInputVisible = true;
this.widgets.multilineInput.value = "";
this._autosizeMultilineInputWidget();
this.timeout(function () { dactyl.focus(this.widgets.multilineInput); }, 10);
}),
get commandMode() this.commandSession && isinstance(modes.main, modes.COMMAND_LINE), get commandMode() this.commandSession && isinstance(modes.main, modes.COMMAND_LINE),

View File

@@ -182,7 +182,6 @@ defineModule("base", {
"Cr", "Cr",
"Cs", "Cs",
"Cu", "Cu",
"DOMPromise",
"ErrorBase", "ErrorBase",
"Finished", "Finished",
"JSMLoader", "JSMLoader",
@@ -762,12 +761,6 @@ function memoize(obj, key, getter) {
} }
} }
let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(),
{ wantGlobalProperties: ["TextDecoder", "TextEncoder"],
sandboxPrototype: this });
var { TextEncoder, TextDecoder, Promise: DOMPromise } = sandbox;
/** /**
* Updates an object with the properties of another object. Getters * Updates an object with the properties of another object. Getters
* and setters are copied as expected. Moreover, any function * and setters are copied as expected. Moreover, any function

View File

@@ -15,6 +15,9 @@ this["import"] = function import_(obj) {
return res; return res;
} }
if (typeof TextEncoder == "undefined")
Components.utils.importGlobalProperties(["TextEncoder", "TextDecoder"]);
// Deal with subScriptLoader prepending crap to loaded URLs // Deal with subScriptLoader prepending crap to loaded URLs
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
function loadSubScript() Services.scriptloader.loadSubScript.apply(null, arguments); function loadSubScript() Services.scriptloader.loadSubScript.apply(null, arguments);

View File

@@ -86,26 +86,28 @@ var Buffer = Module("Buffer", {
* @param {string} pref The name of the preference to return. * @param {string} pref The name of the preference to return.
* @returns {Promise<*>} * @returns {Promise<*>}
*/ */
get: promises.withCallbacks(function get([resolve, reject], pref) { get: function get(pref) {
let val = services.contentPrefs.getCachedByDomainAndName( return new Promise((resolve, reject) => {
self.uri.spec, pref, self.loadContext); let val = services.contentPrefs.getCachedByDomainAndName(
self.uri.spec, pref, self.loadContext);
let found = false; let found = false;
if (val) if (val)
resolve(val.value); resolve(val.value);
else else
services.contentPrefs.getByDomainAndName( services.contentPrefs.getByDomainAndName(
self.uri.spec, pref, self.loadContext, self.uri.spec, pref, self.loadContext,
{ handleCompletion: () => { { handleCompletion: () => {
if (!found) if (!found)
resolve(undefined); resolve(undefined);
}, },
handleResult: (pref) => { handleResult: (pref) => {
found = true; found = true;
resolve(pref.value); resolve(pref.value);
}, },
handleError: reject }); handleError: reject });
}), });
},
/** /**
* Sets a content preference for the given buffer. * Sets a content preference for the given buffer.
@@ -113,26 +115,30 @@ var Buffer = Module("Buffer", {
* @param {string} pref The preference to set. * @param {string} pref The preference to set.
* @param {string} value The value to store. * @param {string} value The value to store.
*/ */
set: promises.withCallbacks(function set([resolve, reject], pref, value) { set: function set(pref, value) {
services.contentPrefs.set( return new Promise((resolve, reject) => {
self.uri.spec, pref, value, self.loadContext, services.contentPrefs.set(
{ handleCompletion: () => {}, self.uri.spec, pref, value, self.loadContext,
handleResult: resolve, { handleCompletion: () => {},
handleError: reject }); handleResult: resolve,
}), handleError: reject });
});
},
/** /**
* Clear a content preference for the given buffer. * Clear a content preference for the given buffer.
* *
* @param {string} pref The preference to clear. * @param {string} pref The preference to clear.
*/ */
clear: promises.withCallbacks(function clear([resolve, reject], pref) { clear: function clear(pref) {
services.contentPrefs.removeByDomainAndName( return new Promise((resolve, reject) => {
self.uri.spec, pref, self.loadContext, services.contentPrefs.removeByDomainAndName(
{ handleCompletion: () => {}, self.uri.spec, pref, self.loadContext,
handleResult: resolve, { handleCompletion: () => {},
handleError: reject }); handleResult: resolve,
}) handleError: reject });
});
}
}; };
}), }),

View File

@@ -140,7 +140,7 @@ var ConfigBase = Class("ConfigBase", {
"options", "options",
"overlay", "overlay",
"prefs", "prefs",
["promises", "Promise", "Task", "promises"], ["promises", "CancelablePromise", "Promise", "Task", "promises"],
"protocol", "protocol",
"sanitizer", "sanitizer",
"services", "services",

View File

@@ -95,9 +95,9 @@ var Modules = function Modules(window) {
if (normal) if (normal)
return create(proto); return create(proto);
sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules,
sandboxName: name || ("Dactyl Sandbox " + ++_id), sandboxName: name || ("Dactyl Sandbox " + ++_id),
wantXrays: true }); wantXrays: true });
// Hack: // Hack:
// sandbox.Object = jsmodules.Object; // sandbox.Object = jsmodules.Object;

View File

@@ -5,7 +5,7 @@
"use strict"; "use strict";
defineModule("promises", { defineModule("promises", {
exports: ["Promise", "Task", "promises"], exports: ["CancelablePromise", "Promise", "Task", "promises"],
require: [] require: []
}); });
@@ -24,6 +24,26 @@ function withCallbacks(fn) {
} }
} }
function CancelablePromise(executor, oncancel) {
let deferred = Promise.defer();
let canceled = new Promise((accept, reject) => {
promises.oncancel(deferred, accept);
});
try {
executor(deferred.resolve, deferred.reject, canceled);
}
catch (e) {
deferred.reject(e);
}
return Object.freeze(Object.create(deferred.promise, {
cancel: {
value: thing => promises.cancel(deferred.promise, thing)
}
}));
}
var Promises = Module("Promises", { var Promises = Module("Promises", {
_cancel: new WeakMap, _cancel: new WeakMap,
@@ -38,7 +58,7 @@ var Promises = Module("Promises", {
let cleanup = this._cancel.get(promise); let cleanup = this._cancel.get(promise);
if (cleanup) { if (cleanup) {
cleanup[0](promise); cleanup[0](promise);
cleanup[1].reject(reason); cleanup[1](reason);
} }
this._cancel.delete(promise); this._cancel.delete(promise);
}, },
@@ -50,16 +70,18 @@ var Promises = Module("Promises", {
* @param {function} fn The cleanup function. * @param {function} fn The cleanup function.
*/ */
oncancel: function oncancel(deferred, fn) { oncancel: function oncancel(deferred, fn) {
this._cancel.set(deferred.promise, [fn, deferred]); this._cancel.set(deferred.promise, [fn, deferred.reject]);
}, },
/** /**
* Returns a promise which resolves after a brief delay. * Returns a promise which resolves after a brief delay.
*/ */
delay: withCallbacks(function delay([accept]) { delay: function delay([accept]) {
let { mainThread } = services.threading; return new Promise(resolve => {
mainThread.dispatch(accept, mainThread.DISPATCH_NORMAL); let { mainThread } = services.threading;
}), mainThread.dispatch(resolve, mainThread.DISPATCH_NORMAL);
});
},
/** /**
* Returns a promise which resolves after the given number of * Returns a promise which resolves after the given number of
@@ -67,9 +89,11 @@ var Promises = Module("Promises", {
* *
* @param {number} delay The number of milliseconds to wait. * @param {number} delay The number of milliseconds to wait.
*/ */
sleep: withCallbacks(function sleep([callback], delay) { sleep: function sleep(delay) {
this.timeout(callback, delay); return new Promise(resolve => {
}), this.timeout(resolve, delay);
});
},
/** /**
* Wraps the given function so that each call spawns a Task. * Wraps the given function so that each call spawns a Task.
@@ -94,25 +118,27 @@ var Promises = Module("Promises", {
* @param {number} pollInterval The poll interval, in milliseconds. * @param {number} pollInterval The poll interval, in milliseconds.
* @default 10 * @default 10
*/ */
waitFor: withCallbacks(function waitFor([accept, reject], test, timeout=null, pollInterval=10) { waitFor: function waitFor(test, timeout=null, pollInterval=10) {
let end = timeout && Date.now() + timeout, result; return new Promise((resolve, reject) => {
let end = timeout && Date.now() + timeout, result;
let timer = services.Timer( let timer = services.Timer(
() => { () => {
try { try {
var result = test(); var result = test();
} }
catch (e) { catch (e) {
timer.cancel(); timer.cancel();
reject(e); reject(e);
} }
if (result) { if (result) {
timer.cancel(); timer.cancel();
accept(result); resolve(result);
} }
}, },
pollInterval, services.Timer.TYPE_REPEATING_SLACK); pollInterval, services.Timer.TYPE_REPEATING_SLACK);
}), });
},
/** /**
* Wraps the given function so that its first argument is an array * Wraps the given function so that its first argument is an array

View File

@@ -828,14 +828,16 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
* @param {string} url The URL to fetch. * @param {string} url The URL to fetch.
* @param {object} params Parameter object, as in #httpGet. * @param {object} params Parameter object, as in #httpGet.
*/ */
fetchUrl: promises.withCallbacks(function fetchUrl([accept, reject, deferred], url, params) { fetchUrl: function fetchUrl(url, params) {
params = update({}, params); return new CancelablePromise((accept, reject, canceled) => {
params.onload = accept; params = update({}, params);
params.onerror = reject; params.onload = accept;
params.onerror = reject;
let req = this.httpGet(url, params); let req = this.httpGet(url, params);
promises.oncancel(deferred, req.cancel); canceled.then(req.cancel);
}), });
},
/** /**
* The identity function. * The identity function.