зеркало из https://github.com/mozilla/gecko-dev.git
Bug 783420 - Stop using devtools' Promise.jsm, and start using toolkit/addon-sdk/promise/core.js; r=past,jwalker
This commit is contained in:
Родитель
5f114a1fb6
Коммит
3e5154de16
|
@ -15,7 +15,6 @@ XPCSHELL_TESTS = unit
|
|||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
browser_browser_basic.js \
|
||||
browser_promise_basic.js \
|
||||
browser_require_basic.js \
|
||||
browser_templater_basic.js \
|
||||
browser_toolbar_basic.js \
|
||||
|
|
|
@ -1,305 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that our Promise implementation works properly
|
||||
|
||||
let tempScope = {};
|
||||
Cu.import("resource://gre/modules/devtools/_Promise.jsm", tempScope);
|
||||
let Promise = tempScope.Promise;
|
||||
|
||||
function test() {
|
||||
addTab("about:blank", function() {
|
||||
info("Starting Promise Tests");
|
||||
testBasic();
|
||||
});
|
||||
}
|
||||
|
||||
var postResolution;
|
||||
|
||||
function testBasic() {
|
||||
postResolution = new Promise();
|
||||
ok(postResolution.isPromise, "We have a promise");
|
||||
ok(!postResolution.isComplete(), "Promise is initially incomplete");
|
||||
ok(!postResolution.isResolved(), "Promise is initially unresolved");
|
||||
ok(!postResolution.isRejected(), "Promise is initially unrejected");
|
||||
|
||||
// Test resolve() *after* then() in the same context
|
||||
var reply = postResolution.then(testPostResolution, fail)
|
||||
.resolve("postResolution");
|
||||
is(reply, postResolution, "return this; working ok");
|
||||
}
|
||||
|
||||
var preResolution;
|
||||
|
||||
function testPostResolution(data) {
|
||||
is(data, "postResolution", "data is postResolution");
|
||||
ok(postResolution.isComplete(), "postResolution Promise is complete");
|
||||
ok(postResolution.isResolved(), "postResolution Promise is resolved");
|
||||
ok(!postResolution.isRejected(), "postResolution Promise is unrejected");
|
||||
|
||||
try {
|
||||
info("Expected double resolve error");
|
||||
postResolution.resolve("double resolve");
|
||||
ok(false, "double resolve");
|
||||
}
|
||||
catch (ex) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Test resolve() *before* then() in the same context
|
||||
preResolution = new Promise();
|
||||
var reply = preResolution.resolve("preResolution")
|
||||
.then(testPreResolution, fail);
|
||||
is(reply, preResolution, "return this; working ok");
|
||||
}
|
||||
|
||||
var laterResolution;
|
||||
|
||||
function testPreResolution(data) {
|
||||
is(data, "preResolution", "data is preResolution");
|
||||
ok(preResolution.isComplete(), "preResolution Promise is complete");
|
||||
ok(preResolution.isResolved(), "preResolution Promise is resolved");
|
||||
ok(!preResolution.isRejected(), "preResolution Promise is unrejected");
|
||||
|
||||
// Test resolve() *after* then() in a later context
|
||||
laterResolution = new Promise();
|
||||
laterResolution.then(testLaterResolution, fail);
|
||||
executeSoon(function() {
|
||||
laterResolution.resolve("laterResolution");
|
||||
});
|
||||
}
|
||||
|
||||
var laterRejection;
|
||||
|
||||
function testLaterResolution(data) {
|
||||
is(data, "laterResolution", "data is laterResolution");
|
||||
ok(laterResolution.isComplete(), "laterResolution Promise is complete");
|
||||
ok(laterResolution.isResolved(), "laterResolution Promise is resolved");
|
||||
ok(!laterResolution.isRejected(), "laterResolution Promise is unrejected");
|
||||
|
||||
// Test reject() *after* then() in a later context
|
||||
laterRejection = new Promise().then(fail, testLaterRejection);
|
||||
executeSoon(function() {
|
||||
laterRejection.reject("laterRejection");
|
||||
});
|
||||
}
|
||||
|
||||
function testLaterRejection(data) {
|
||||
is(data, "laterRejection", "data is laterRejection");
|
||||
ok(laterRejection.isComplete(), "laterRejection Promise is complete");
|
||||
ok(!laterRejection.isResolved(), "laterRejection Promise is unresolved");
|
||||
ok(laterRejection.isRejected(), "laterRejection Promise is rejected");
|
||||
|
||||
// Test chaining
|
||||
var orig = new Promise();
|
||||
orig.chainPromise(function(data) {
|
||||
is(data, "origData", "data is origData");
|
||||
return data.replace(/orig/, "new");
|
||||
}).then(function(data) {
|
||||
is(data, "newData", "data is newData");
|
||||
testChain();
|
||||
});
|
||||
orig.resolve("origData");
|
||||
}
|
||||
|
||||
var member1;
|
||||
var member2;
|
||||
var member3;
|
||||
var laterGroup;
|
||||
|
||||
function testChain() {
|
||||
// Test an empty group
|
||||
var empty1 = Promise.group();
|
||||
ok(empty1.isComplete(), "empty1 Promise is complete");
|
||||
ok(empty1.isResolved(), "empty1 Promise is resolved");
|
||||
ok(!empty1.isRejected(), "empty1 Promise is unrejected");
|
||||
|
||||
// Test a group with no members
|
||||
var empty2 = Promise.group([]);
|
||||
ok(empty2.isComplete(), "empty2 Promise is complete");
|
||||
ok(empty2.isResolved(), "empty2 Promise is resolved");
|
||||
ok(!empty2.isRejected(), "empty2 Promise is unrejected");
|
||||
|
||||
// Test grouping using resolve() in a later context
|
||||
member1 = new Promise();
|
||||
member2 = new Promise();
|
||||
member3 = new Promise();
|
||||
laterGroup = Promise.group(member1, member2, member3);
|
||||
laterGroup.then(testLaterGroup, fail);
|
||||
|
||||
member1.then(function(data) {
|
||||
is(data, "member1", "member1 is member1");
|
||||
executeSoon(function() {
|
||||
member2.resolve("member2");
|
||||
});
|
||||
}, fail);
|
||||
member2.then(function(data) {
|
||||
is(data, "member2", "member2 is member2");
|
||||
executeSoon(function() {
|
||||
member3.resolve("member3");
|
||||
});
|
||||
}, fail);
|
||||
member3.then(function(data) {
|
||||
is(data, "member3", "member3 is member3");
|
||||
// The group should now fire
|
||||
}, fail);
|
||||
executeSoon(function() {
|
||||
member1.resolve("member1");
|
||||
});
|
||||
}
|
||||
|
||||
var tidyGroup;
|
||||
|
||||
function testLaterGroup(data) {
|
||||
is(data[0], "member1", "member1 is member1");
|
||||
is(data[1], "member2", "member2 is member2");
|
||||
is(data[2], "member3", "member3 is member3");
|
||||
is(data.length, 3, "data.length is right");
|
||||
ok(laterGroup.isComplete(), "laterGroup Promise is complete");
|
||||
ok(laterGroup.isResolved(), "laterGroup Promise is resolved");
|
||||
ok(!laterGroup.isRejected(), "laterGroup Promise is unrejected");
|
||||
|
||||
// Test grouping resolve() *before* then() in the same context
|
||||
tidyGroup = Promise.group([
|
||||
postResolution, preResolution, laterResolution,
|
||||
member1, member2, member3, laterGroup
|
||||
]);
|
||||
tidyGroup.then(testTidyGroup, fail);
|
||||
}
|
||||
|
||||
var failGroup;
|
||||
|
||||
function testTidyGroup(data) {
|
||||
is(data[0], "postResolution", "postResolution is postResolution");
|
||||
is(data[1], "preResolution", "preResolution is preResolution");
|
||||
is(data[2], "laterResolution", "laterResolution is laterResolution");
|
||||
is(data[3], "member1", "member1 is member1");
|
||||
is(data[6][1], "member2", "laterGroup is laterGroup");
|
||||
is(data.length, 7, "data.length is right");
|
||||
ok(tidyGroup.isComplete(), "tidyGroup Promise is complete");
|
||||
ok(tidyGroup.isResolved(), "tidyGroup Promise is resolved");
|
||||
ok(!tidyGroup.isRejected(), "tidyGroup Promise is unrejected");
|
||||
|
||||
// Test grouping resolve() *before* then() in the same context
|
||||
failGroup = Promise.group(postResolution, laterRejection);
|
||||
failGroup.then(fail, testFailGroup);
|
||||
}
|
||||
|
||||
function testFailGroup(data) {
|
||||
is(data, "laterRejection", "laterRejection is laterRejection");
|
||||
|
||||
postResolution = undefined;
|
||||
preResolution = undefined;
|
||||
laterResolution = undefined;
|
||||
member1 = undefined;
|
||||
member2 = undefined;
|
||||
member3 = undefined;
|
||||
laterGroup = undefined;
|
||||
laterRejection = undefined;
|
||||
|
||||
testTrap();
|
||||
}
|
||||
|
||||
function testTrap() {
|
||||
var p = new Promise();
|
||||
var message = "Expected exception";
|
||||
p.chainPromise(
|
||||
function() {
|
||||
throw new Error(message);
|
||||
}).trap(
|
||||
function(aError) {
|
||||
is(aError instanceof Error, true, "trap received exception");
|
||||
is(aError.message, message, "trap received correct exception");
|
||||
return 1;
|
||||
}).chainPromise(
|
||||
function(aResult) {
|
||||
is(aResult, 1, "trap restored correct result");
|
||||
testAlways();
|
||||
});
|
||||
p.resolve();
|
||||
}
|
||||
|
||||
function testAlways() {
|
||||
var shouldbeTrue1 = false;
|
||||
var shouldbeTrue2 = false;
|
||||
var p = new Promise();
|
||||
p.chainPromise(
|
||||
function() {
|
||||
throw new Error();
|
||||
}
|
||||
).chainPromise(// Promise rejected, should not be executed
|
||||
function() {
|
||||
ok(false, "This should not be executed");
|
||||
}
|
||||
).always(
|
||||
function(x) {
|
||||
shouldbeTrue1 = true;
|
||||
return "random value";
|
||||
}
|
||||
).trap(
|
||||
function(arg) {
|
||||
ok((arg instanceof Error), "The random value should be ignored");
|
||||
return 1;// We should still have this result later
|
||||
}
|
||||
).trap(
|
||||
function() {
|
||||
ok(false, "This should not be executed 2");
|
||||
}
|
||||
).always(
|
||||
function() {
|
||||
shouldbeTrue2 = true;
|
||||
}
|
||||
).then(
|
||||
function(aResult){
|
||||
ok(shouldbeTrue1, "First always must be executed");
|
||||
ok(shouldbeTrue2, "Second always must be executed");
|
||||
is(aResult, 1, "Result should be unaffected by always");
|
||||
|
||||
testComplete();
|
||||
}
|
||||
);
|
||||
p.resolve();
|
||||
}
|
||||
|
||||
function fail() {
|
||||
gBrowser.removeCurrentTab();
|
||||
info("Failed Promise Tests");
|
||||
ok(false, "fail called");
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* We wish to launch all tests with several configurations (at the moment,
|
||||
* non-debug and debug mode).
|
||||
*
|
||||
* If 0, we have not completed any test yet.
|
||||
* If 1, we have completed the tests in non-debug mode.
|
||||
* If 2, we have also completed the tests in debug mode.
|
||||
*/
|
||||
var configurationTestComplete = 0;
|
||||
function testComplete() {
|
||||
switch (configurationTestComplete) {
|
||||
case 0:
|
||||
info("Finished run in non-debug mode");
|
||||
configurationTestComplete = 1;
|
||||
Promise.Debug.setDebug(true);
|
||||
window.setTimeout(testBasic, 0);
|
||||
return;
|
||||
case 1:
|
||||
info("Finished run in debug mode");
|
||||
configurationTestComplete = 2;
|
||||
Promise.Debug.setDebug(false);
|
||||
window.setTimeout(finished, 0);
|
||||
return;
|
||||
default:
|
||||
ok(false, "Internal error in testComplete "+configurationTestComplete);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function finished() {
|
||||
gBrowser.removeCurrentTab();
|
||||
info("Finishing Promise Tests");
|
||||
finish();
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
var imports = {};
|
||||
Cu.import("resource:///modules/devtools/Templater.jsm", imports);
|
||||
Cu.import("resource://gre/modules/devtools/_Promise.jsm", imports);
|
||||
Cu.import("resource://gre/modules/commonjs/promise/core.js", imports);
|
||||
|
||||
function test() {
|
||||
addTab("http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html", function() {
|
||||
|
@ -278,9 +278,9 @@ var tests = [
|
|||
];
|
||||
|
||||
function delayReply(data) {
|
||||
var p = new imports.Promise();
|
||||
var d = imports.Promise.defer();
|
||||
executeSoon(function() {
|
||||
p.resolve(data);
|
||||
d.resolve(data);
|
||||
});
|
||||
return p;
|
||||
return d.promise;
|
||||
}
|
||||
|
|
|
@ -1,409 +0,0 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "Promise" ];
|
||||
|
||||
/**
|
||||
* Create an unfulfilled promise
|
||||
*
|
||||
* @param {*=} aTrace A debugging value
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
this.Promise = function Promise(aTrace) {
|
||||
this._status = Promise.PENDING;
|
||||
this._value = undefined;
|
||||
this._onSuccessHandlers = [];
|
||||
this._onErrorHandlers = [];
|
||||
this._trace = aTrace;
|
||||
|
||||
// Debugging help
|
||||
if (Promise.Debug._debug) {
|
||||
this._id = Promise.Debug._nextId++;
|
||||
Promise.Debug._outstanding[this._id] = this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging options and tools.
|
||||
*/
|
||||
Promise.Debug = {
|
||||
/**
|
||||
* Set current debugging mode.
|
||||
*
|
||||
* @param {boolean} value If |true|, maintain _nextId, _outstanding, _recent.
|
||||
* Otherwise, cleanup debugging data.
|
||||
*/
|
||||
setDebug: function(value) {
|
||||
Promise.Debug._debug = value;
|
||||
if (!value) {
|
||||
Promise.Debug._outstanding = [];
|
||||
Promise.Debug._recent = [];
|
||||
}
|
||||
},
|
||||
|
||||
_debug: false,
|
||||
|
||||
/**
|
||||
* We give promises and ID so we can track which are outstanding.
|
||||
*/
|
||||
_nextId: 0,
|
||||
|
||||
/**
|
||||
* Outstanding promises. Handy for debugging (only).
|
||||
*/
|
||||
_outstanding: [],
|
||||
|
||||
/**
|
||||
* Recently resolved promises. Also for debugging only.
|
||||
*/
|
||||
_recent: []
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A promise can be in one of 2 states.
|
||||
* The ERROR and SUCCESS states are terminal, the PENDING state is the only
|
||||
* start state.
|
||||
*/
|
||||
Promise.ERROR = -1;
|
||||
Promise.PENDING = 0;
|
||||
Promise.SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* Yeay for RTTI
|
||||
*/
|
||||
Promise.prototype.isPromise = true;
|
||||
|
||||
/**
|
||||
* Have we either been resolve()ed or reject()ed?
|
||||
*/
|
||||
Promise.prototype.isComplete = function() {
|
||||
return this._status != Promise.PENDING;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we resolve()ed?
|
||||
*/
|
||||
Promise.prototype.isResolved = function() {
|
||||
return this._status == Promise.SUCCESS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we reject()ed?
|
||||
*/
|
||||
Promise.prototype.isRejected = function() {
|
||||
return this._status == Promise.ERROR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Take the specified action of fulfillment of a promise, and (optionally)
|
||||
* a different action on promise rejection
|
||||
*/
|
||||
Promise.prototype.then = function(onSuccess, onError) {
|
||||
if (typeof onSuccess === 'function') {
|
||||
if (this._status === Promise.SUCCESS) {
|
||||
onSuccess.call(null, this._value);
|
||||
}
|
||||
else if (this._status === Promise.PENDING) {
|
||||
this._onSuccessHandlers.push(onSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onError === 'function') {
|
||||
if (this._status === Promise.ERROR) {
|
||||
onError.call(null, this._value);
|
||||
}
|
||||
else if (this._status === Promise.PENDING) {
|
||||
this._onErrorHandlers.push(onError);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Like then() except that rather than returning <tt>this</tt> we return
|
||||
* a promise which resolves when the original promise resolves
|
||||
*/
|
||||
Promise.prototype.chainPromise = function(onSuccess) {
|
||||
var chain = new Promise();
|
||||
chain._chainedFrom = this;
|
||||
this.then(function(data) {
|
||||
try {
|
||||
chain.resolve(onSuccess(data));
|
||||
}
|
||||
catch (ex) {
|
||||
chain.reject(ex);
|
||||
}
|
||||
}, function(ex) {
|
||||
chain.reject(ex);
|
||||
});
|
||||
return chain;
|
||||
};
|
||||
|
||||
/**
|
||||
* Supply the fulfillment of a promise
|
||||
*/
|
||||
Promise.prototype.resolve = function(data) {
|
||||
return this._complete(this._onSuccessHandlers,
|
||||
Promise.SUCCESS, data, 'resolve');
|
||||
};
|
||||
|
||||
/**
|
||||
* Renege on a promise
|
||||
*/
|
||||
Promise.prototype.reject = function(data) {
|
||||
return this._complete(this._onErrorHandlers, Promise.ERROR, data, 'reject');
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal method to be called on resolve() or reject()
|
||||
* @private
|
||||
*/
|
||||
Promise.prototype._complete = function(list, status, data, name) {
|
||||
// Complain if we've already been completed
|
||||
if (this._status != Promise.PENDING) {
|
||||
Promise._error("Promise complete.", "Attempted ", name, "() with ", data);
|
||||
Promise._error("Previous status: ", this._status, ", value =", this._value);
|
||||
throw new Error('Promise already complete');
|
||||
}
|
||||
|
||||
if (list.length == 0 && status == Promise.ERROR) {
|
||||
var frame;
|
||||
var text;
|
||||
|
||||
//Complain if a rejection is ignored
|
||||
//(this is the equivalent of an empty catch-all clause)
|
||||
Promise._error("Promise rejection ignored and silently dropped", data);
|
||||
if (data.stack) {// This looks like an exception. Try harder to display it
|
||||
if (data.fileName && data.lineNumber) {
|
||||
Promise._error("Error originating at", data.fileName,
|
||||
", line", data.lineNumber );
|
||||
}
|
||||
try {
|
||||
for (frame = data.stack; frame; frame = frame.caller) {
|
||||
text += frame + "\n";
|
||||
}
|
||||
Promise._error("Attempting to extract exception stack", text);
|
||||
} catch (x) {
|
||||
Promise._error("Could not extract exception stack.");
|
||||
}
|
||||
} else {
|
||||
Promise._error("Exception stack not available.");
|
||||
}
|
||||
if (Components && Components.stack) {
|
||||
try {
|
||||
text = "";
|
||||
for (frame = Components.stack; frame; frame = frame.caller) {
|
||||
text += frame + "\n";
|
||||
}
|
||||
Promise._error("Attempting to extract current stack", text);
|
||||
} catch (x) {
|
||||
Promise._error("Could not extract current stack.");
|
||||
}
|
||||
} else {
|
||||
Promise._error("Current stack not available.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this._status = status;
|
||||
this._value = data;
|
||||
|
||||
// Call all the handlers, and then delete them
|
||||
list.forEach(function(handler) {
|
||||
handler.call(null, this._value);
|
||||
}, this);
|
||||
delete this._onSuccessHandlers;
|
||||
delete this._onErrorHandlers;
|
||||
|
||||
// Remove the given {promise} from the _outstanding list, and add it to the
|
||||
// _recent list, pruning more than 20 recent promises from that list
|
||||
delete Promise.Debug._outstanding[this._id];
|
||||
// The original code includes this very useful debugging aid, however there
|
||||
// is concern that it will create a memory leak, so we leave it out here.
|
||||
/*
|
||||
Promise._recent.push(this);
|
||||
while (Promise._recent.length > 20) {
|
||||
Promise._recent.shift();
|
||||
}
|
||||
*/
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Log an error on the most appropriate channel.
|
||||
*
|
||||
* If the console is available, this method uses |console.warn|. Otherwise,
|
||||
* this method falls back to |dump|.
|
||||
*
|
||||
* @param {...*} items Items to log.
|
||||
*/
|
||||
Promise._error = null;
|
||||
if (typeof console != "undefined" && console.warn) {
|
||||
Promise._error = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args.unshift("Promise");
|
||||
console.warn.call(console, args);
|
||||
};
|
||||
} else {
|
||||
Promise._error = function() {
|
||||
var i;
|
||||
var len = arguments.length;
|
||||
dump("Promise: ");
|
||||
for (i = 0; i < len; ++i) {
|
||||
dump(arguments[i]+" ");
|
||||
}
|
||||
dump("\n");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an array of promises and returns a promise that that is fulfilled once
|
||||
* all the promises in the array are fulfilled
|
||||
* @param promiseList The array of promises
|
||||
* @return the promise that is fulfilled when all the array is fulfilled
|
||||
*/
|
||||
Promise.group = function(promiseList) {
|
||||
if (!Array.isArray(promiseList)) {
|
||||
promiseList = Array.prototype.slice.call(arguments);
|
||||
}
|
||||
|
||||
// If the original array has nothing in it, return now to avoid waiting
|
||||
if (promiseList.length === 0) {
|
||||
return new Promise().resolve([]);
|
||||
}
|
||||
|
||||
var groupPromise = new Promise();
|
||||
var results = [];
|
||||
var fulfilled = 0;
|
||||
|
||||
var onSuccessFactory = function(index) {
|
||||
return function(data) {
|
||||
results[index] = data;
|
||||
fulfilled++;
|
||||
// If the group has already failed, silently drop extra results
|
||||
if (groupPromise._status !== Promise.ERROR) {
|
||||
if (fulfilled === promiseList.length) {
|
||||
groupPromise.resolve(results);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
promiseList.forEach(function(promise, index) {
|
||||
var onSuccess = onSuccessFactory(index);
|
||||
var onError = groupPromise.reject.bind(groupPromise);
|
||||
promise.then(onSuccess, onError);
|
||||
});
|
||||
|
||||
return groupPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Trap errors.
|
||||
*
|
||||
* This function serves as an asynchronous counterpart to |catch|.
|
||||
*
|
||||
* Example:
|
||||
* myPromise.chainPromise(a) //May reject
|
||||
* .chainPromise(b) //May reject
|
||||
* .chainPromise(c) //May reject
|
||||
* .trap(d) //Catch any rejection from a, b or c
|
||||
* .chainPromise(e) //If either a, b and c or
|
||||
* //d has resolved, execute
|
||||
*
|
||||
* Scenario 1:
|
||||
* If a, b, c resolve, e is executed as if d had not been added.
|
||||
*
|
||||
* Scenario 2:
|
||||
* If a, b or c rejects, d is executed. If d resolves, we proceed
|
||||
* with e as if nothing had happened. Otherwise, we proceed with
|
||||
* the rejection of d.
|
||||
*
|
||||
* @param {Function} aTrap Called if |this| promise is rejected,
|
||||
* with one argument: the rejection.
|
||||
* @return {Promise} A new promise. This promise resolves if all
|
||||
* previous promises have resolved or if |aTrap| succeeds.
|
||||
*/
|
||||
Promise.prototype.trap = function(aTrap) {
|
||||
var promise = new Promise();
|
||||
var resolve = Promise.prototype.resolve.bind(promise);
|
||||
var reject = function(aRejection) {
|
||||
try {
|
||||
//Attempt to handle issue
|
||||
var result = aTrap.call(aTrap, aRejection);
|
||||
promise.resolve(result);
|
||||
} catch (x) {
|
||||
promise.reject(x);
|
||||
}
|
||||
};
|
||||
this.then(resolve, reject);
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute regardless of errors.
|
||||
*
|
||||
* This function serves as an asynchronous counterpart to |finally|.
|
||||
*
|
||||
* Example:
|
||||
* myPromise.chainPromise(a) //May reject
|
||||
* .chainPromise(b) //May reject
|
||||
* .chainPromise(c) //May reject
|
||||
* .always(d) //Executed regardless
|
||||
* .chainPromise(e)
|
||||
*
|
||||
* Whether |a|, |b| or |c| resolve or reject, |d| is executed.
|
||||
*
|
||||
* @param {Function} aTrap Called regardless of whether |this|
|
||||
* succeeds or fails.
|
||||
* @return {Promise} A new promise. This promise holds the same
|
||||
* resolution/rejection as |this|.
|
||||
*/
|
||||
Promise.prototype.always = function(aTrap) {
|
||||
var promise = new Promise();
|
||||
var resolve = function(result) {
|
||||
try {
|
||||
aTrap.call(aTrap);
|
||||
promise.resolve(result);
|
||||
} catch (x) {
|
||||
promise.reject(x);
|
||||
}
|
||||
};
|
||||
var reject = function(result) {
|
||||
try {
|
||||
aTrap.call(aTrap);
|
||||
promise.reject(result);
|
||||
} catch (x) {
|
||||
promise.reject(result);
|
||||
}
|
||||
};
|
||||
this.then(resolve, reject);
|
||||
return promise;
|
||||
};
|
||||
|
||||
|
||||
Promise.prototype.toString = function() {
|
||||
var status;
|
||||
switch (this._status) {
|
||||
case Promise.PENDING:
|
||||
status = "pending";
|
||||
break;
|
||||
case Promise.SUCCESS:
|
||||
status = "resolved";
|
||||
break;
|
||||
case Promise.ERROR:
|
||||
status = "rejected";
|
||||
break;
|
||||
default:
|
||||
status = "invalid status: "+this._status;
|
||||
}
|
||||
return "[Promise " + this._id + " (" + status + ")]";
|
||||
};
|
|
@ -1346,27 +1346,23 @@ SourceActor.prototype = {
|
|||
* Handler for the "source" packet.
|
||||
*/
|
||||
onSource: function SA_onSource(aRequest) {
|
||||
this
|
||||
return this
|
||||
._loadSource()
|
||||
.chainPromise(function(aSource) {
|
||||
.then(function(aSource) {
|
||||
return this._threadActor.createValueGrip(
|
||||
aSource, this.threadActor.threadLifetimePool);
|
||||
}.bind(this))
|
||||
.chainPromise(function (aSourceGrip) {
|
||||
.then(function (aSourceGrip) {
|
||||
return {
|
||||
from: this.actorID,
|
||||
source: aSourceGrip
|
||||
};
|
||||
}.bind(this))
|
||||
.trap(function (aError) {
|
||||
}.bind(this), function (aError) {
|
||||
return {
|
||||
"from": this.actorID,
|
||||
"error": "loadSourceError",
|
||||
"message": "Could not load the source for " + this._script.url + "."
|
||||
};
|
||||
}.bind(this))
|
||||
.chainPromise(function (aPacket) {
|
||||
this.conn.send(aPacket);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -1404,7 +1400,7 @@ SourceActor.prototype = {
|
|||
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
|
||||
*/
|
||||
_loadSource: function SA__loadSource() {
|
||||
let promise = new Promise();
|
||||
let deferred = defer();
|
||||
let url = this._script.url;
|
||||
let scheme;
|
||||
try {
|
||||
|
@ -1424,16 +1420,16 @@ SourceActor.prototype = {
|
|||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
promise.reject(new Error("Request failed"));
|
||||
deferred.reject(new Error("Request failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
promise.resolve(this._convertToUnicode(source));
|
||||
deferred.resolve(this._convertToUnicode(source));
|
||||
aStream.close();
|
||||
}.bind(this));
|
||||
} catch (ex) {
|
||||
promise.reject(new Error("Request failed"));
|
||||
deferred.reject(new Error("Request failed"));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1451,7 +1447,7 @@ SourceActor.prototype = {
|
|||
let streamListener = {
|
||||
onStartRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
promise.reject("Request failed");
|
||||
deferred.reject("Request failed");
|
||||
}
|
||||
},
|
||||
onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) {
|
||||
|
@ -1459,12 +1455,12 @@ SourceActor.prototype = {
|
|||
},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
promise.reject("Request failed");
|
||||
deferred.reject("Request failed");
|
||||
return;
|
||||
}
|
||||
|
||||
promise.resolve(this._convertToUnicode(chunks.join(""),
|
||||
channel.contentCharset));
|
||||
deferred.resolve(this._convertToUnicode(chunks.join(""),
|
||||
channel.contentCharset));
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
|
@ -1473,7 +1469,7 @@ SourceActor.prototype = {
|
|||
break;
|
||||
}
|
||||
|
||||
return promise;
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -24,7 +24,8 @@ let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
|||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
addDebuggerToGlobal(this);
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/_Promise.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/promise/core.js");
|
||||
const { defer, resolve, reject } = Promise;
|
||||
|
||||
function dumpn(str) {
|
||||
if (wantLogging) {
|
||||
|
@ -664,16 +665,17 @@ DebuggerServerConnection.prototype = {
|
|||
}
|
||||
|
||||
if (!ret) {
|
||||
// XXX: The actor wasn't ready to reply yet, don't process new
|
||||
// requests until it does.
|
||||
// This should become an error once we've converted every user
|
||||
// of this to promises in bug 794078.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ret.from) {
|
||||
ret.from = aPacket.to;
|
||||
}
|
||||
|
||||
this.transport.send(ret);
|
||||
resolve(ret).then(function(returnPacket) {
|
||||
if (!returnPacket.from) {
|
||||
returnPacket.from = aPacket.to;
|
||||
}
|
||||
this.transport.send(returnPacket);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче