2012-06-03 04:43:42 +00:00
|
|
|
|
// vim:ts=4:sts=4:sw=4:
|
|
|
|
|
/*!
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2009-2012 Kris Kowal under the terms of the MIT
|
|
|
|
|
* license found at http://github.com/kriskowal/q/raw/master/LICENSE
|
|
|
|
|
*
|
|
|
|
|
* With parts by Tyler Close
|
|
|
|
|
* Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
|
|
|
|
|
* at http://www.opensource.org/licenses/mit-license.html
|
|
|
|
|
* Forked at ref_send.js version: 2009-05-11
|
|
|
|
|
*
|
|
|
|
|
* With parts by Mark Miller
|
|
|
|
|
* Copyright (C) 2011 Google Inc.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
(function (definition) {
|
|
|
|
|
// Turn off strict mode for this function so we can assign to global.Q
|
|
|
|
|
/*jshint strict: false*/
|
|
|
|
|
|
|
|
|
|
// This file will function properly as a <script> tag, or a module
|
|
|
|
|
// using CommonJS and NodeJS or RequireJS module formats. In
|
|
|
|
|
// Common/Node/RequireJS, the module exports the Q API and when
|
|
|
|
|
// executed as a simple <script>, it creates a Q global instead.
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
// Montage Require
|
|
|
|
|
if (typeof bootstrap === "function") {
|
|
|
|
|
bootstrap("promise", definition);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
// CommonJS
|
|
|
|
|
} else if (typeof exports === "object") {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
module.exports = definition();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
// RequireJS
|
|
|
|
|
} else if (typeof define === "function") {
|
|
|
|
|
define(definition);
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
// SES (Secure EcmaScript)
|
|
|
|
|
} else if (typeof ses !== "undefined") {
|
|
|
|
|
if (!ses.ok()) {
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
ses.makeQ = definition;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
|
2012-07-10 19:27:38 +00:00
|
|
|
|
// Mozilla JSM
|
|
|
|
|
} else if (~String(this).indexOf('BackstagePass')) {
|
|
|
|
|
EXPORTED_SYMBOLS = ["Q"];
|
|
|
|
|
|
|
|
|
|
// Q expects an implementation of setTimeout
|
2013-06-06 23:31:09 +00:00
|
|
|
|
setTimeout = new function() {
|
|
|
|
|
// We need to maintain references to running nsITimers. Otherwise, they can
|
|
|
|
|
// get garbage collected before they fire.
|
|
|
|
|
var _runningTimers = [];
|
|
|
|
|
|
|
|
|
|
return function setTimeout(func, ms) {
|
|
|
|
|
var useMethodjit = Components.utils.methodjit,
|
|
|
|
|
timer = Components.classes["@mozilla.org/timer;1"].
|
|
|
|
|
createInstance(Components.interfaces.nsITimer);
|
|
|
|
|
timer.initWithCallback({"notify":function() {
|
2013-06-06 23:38:48 +00:00
|
|
|
|
// XXX Remove when we drop support for Fx <24
|
|
|
|
|
if(useMethodjit !== undefined) Components.utils.methodjit = useMethodjit;
|
2013-06-06 23:31:09 +00:00
|
|
|
|
|
|
|
|
|
// Remove timer from array so it can be garbage collected
|
|
|
|
|
_runningTimers.splice(_runningTimers.indexOf(timer), 1);
|
|
|
|
|
|
|
|
|
|
// Execute callback function
|
|
|
|
|
try {
|
|
|
|
|
func();
|
|
|
|
|
} catch(err) {
|
|
|
|
|
// Rethrow errors that occur so that they appear in the error
|
|
|
|
|
// console with the appropriate name and line numbers. While the
|
|
|
|
|
// the errors appear without this, the line numbers get eaten.
|
|
|
|
|
var scriptError = Components.classes["@mozilla.org/scripterror;1"]
|
|
|
|
|
.createInstance(Components.interfaces.nsIScriptError);
|
|
|
|
|
scriptError.init(
|
|
|
|
|
err.message || err.toString(),
|
|
|
|
|
err.fileName || err.filename || null,
|
|
|
|
|
null,
|
|
|
|
|
err.lineNumber || null,
|
|
|
|
|
null,
|
|
|
|
|
scriptError.errorFlag,
|
|
|
|
|
'component javascript'
|
|
|
|
|
);
|
|
|
|
|
Components.classes["@mozilla.org/consoleservice;1"]
|
|
|
|
|
.getService(Components.interfaces.nsIConsoleService)
|
|
|
|
|
.logMessage(scriptError);
|
|
|
|
|
}
|
|
|
|
|
}}, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
|
_runningTimers.push(timer);
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q = definition();
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
// <script>
|
|
|
|
|
} else {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q = definition();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
})(function () {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
"use strict";
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
// All code after this point will be filtered from stack traces reported
|
|
|
|
|
// by Q.
|
|
|
|
|
var qStartingLine = captureLine();
|
|
|
|
|
var qFileName;
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
// shims
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
// used for fallback in "allResolved"
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var noop = function () {};
|
|
|
|
|
|
|
|
|
|
// use the fastest possible means to execute a task in a future turn
|
|
|
|
|
// of the event loop.
|
|
|
|
|
var nextTick;
|
|
|
|
|
if (typeof process !== "undefined") {
|
|
|
|
|
// node
|
|
|
|
|
nextTick = process.nextTick;
|
|
|
|
|
} else if (typeof setImmediate === "function") {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
// In IE10, or use https://github.com/NobleJS/setImmediate
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (typeof window !== "undefined") {
|
|
|
|
|
nextTick = setImmediate.bind(window);
|
|
|
|
|
} else {
|
|
|
|
|
nextTick = setImmediate;
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
} else {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
(function () {
|
|
|
|
|
// linked list of tasks (single, with head node)
|
|
|
|
|
var head = {task: void 0, next: null}, tail = head,
|
|
|
|
|
maxPendingTicks = 2, pendingTicks = 0, queuedTasks = 0, usedTicks = 0,
|
|
|
|
|
requestTick;
|
|
|
|
|
|
|
|
|
|
function onTick() {
|
|
|
|
|
// In case of multiple tasks ensure at least one subsequent tick
|
|
|
|
|
// to handle remaining tasks in case one throws.
|
|
|
|
|
--pendingTicks;
|
|
|
|
|
|
|
|
|
|
if (++usedTicks >= maxPendingTicks) {
|
|
|
|
|
// Amortize latency after thrown exceptions.
|
|
|
|
|
usedTicks = 0;
|
|
|
|
|
maxPendingTicks *= 4; // fast grow!
|
|
|
|
|
var expectedTicks = queuedTasks && Math.min(queuedTasks - 1, maxPendingTicks);
|
|
|
|
|
while (pendingTicks < expectedTicks) {
|
|
|
|
|
++pendingTicks;
|
|
|
|
|
requestTick();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (queuedTasks) {
|
|
|
|
|
--queuedTasks; // decrement here to ensure it's never negative
|
|
|
|
|
head = head.next;
|
|
|
|
|
var task = head.task;
|
|
|
|
|
head.task = void 0;
|
|
|
|
|
task();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usedTicks = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nextTick = function (task) {
|
|
|
|
|
tail = tail.next = {task: task, next: null};
|
|
|
|
|
if (pendingTicks < ++queuedTasks && pendingTicks < maxPendingTicks) {
|
|
|
|
|
++pendingTicks;
|
|
|
|
|
requestTick();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (typeof MessageChannel !== "undefined") {
|
|
|
|
|
// modern browsers
|
|
|
|
|
// http://www.nonblocking.io/2011/06/windownexttick.html
|
|
|
|
|
var channel = new MessageChannel();
|
|
|
|
|
channel.port1.onmessage = onTick;
|
|
|
|
|
requestTick = function () {
|
|
|
|
|
channel.port2.postMessage(0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// old browsers
|
|
|
|
|
requestTick = function () {
|
|
|
|
|
setTimeout(onTick, 0);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
})();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Attempt to make generics safe in the face of downstream
|
|
|
|
|
// modifications.
|
|
|
|
|
// There is no situation where this is necessary.
|
|
|
|
|
// If you need a security guarantee, these primordials need to be
|
|
|
|
|
// deeply frozen anyway, and if you don’t need a security guarantee,
|
|
|
|
|
// this is just plain paranoid.
|
|
|
|
|
// However, this does have the nice side-effect of reducing the size
|
|
|
|
|
// of the code by reducing x.call() to merely x(), eliminating many
|
|
|
|
|
// hard-to-minify characters.
|
|
|
|
|
// See Mark Miller’s explanation of what this does.
|
|
|
|
|
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
|
2013-02-17 03:43:39 +00:00
|
|
|
|
function uncurryThis(f) {
|
|
|
|
|
var call = Function.call;
|
|
|
|
|
return function () {
|
|
|
|
|
return call.apply(f, arguments);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
// This is equivalent, but slower:
|
|
|
|
|
// uncurryThis = Function_bind.bind(Function_bind.call);
|
|
|
|
|
// http://jsperf.com/uncurrythis
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
var array_slice = uncurryThis(Array.prototype.slice);
|
|
|
|
|
|
|
|
|
|
var array_reduce = uncurryThis(
|
|
|
|
|
Array.prototype.reduce || function (callback, basis) {
|
|
|
|
|
var index = 0,
|
|
|
|
|
length = this.length;
|
|
|
|
|
// concerning the initial value, if one is not provided
|
|
|
|
|
if (arguments.length === 1) {
|
|
|
|
|
// seek to the first value in the array, accounting
|
|
|
|
|
// for the possibility that is is a sparse array
|
|
|
|
|
do {
|
|
|
|
|
if (index in this) {
|
|
|
|
|
basis = this[index++];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (++index >= length) {
|
|
|
|
|
throw new TypeError();
|
|
|
|
|
}
|
|
|
|
|
} while (1);
|
|
|
|
|
}
|
|
|
|
|
// reduce
|
|
|
|
|
for (; index < length; index++) {
|
|
|
|
|
// account for the possibility that the array is sparse
|
|
|
|
|
if (index in this) {
|
|
|
|
|
basis = callback(basis, this[index], index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return basis;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var array_indexOf = uncurryThis(
|
|
|
|
|
Array.prototype.indexOf || function (value) {
|
|
|
|
|
// not a very good shim, but good enough for our one use of it
|
|
|
|
|
for (var i = 0; i < this.length; i++) {
|
|
|
|
|
if (this[i] === value) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var array_map = uncurryThis(
|
|
|
|
|
Array.prototype.map || function (callback, thisp) {
|
|
|
|
|
var self = this;
|
|
|
|
|
var collect = [];
|
|
|
|
|
array_reduce(self, function (undefined, value, index) {
|
|
|
|
|
collect.push(callback.call(thisp, value, index, self));
|
|
|
|
|
}, void 0);
|
|
|
|
|
return collect;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var object_create = Object.create || function (prototype) {
|
|
|
|
|
function Type() { }
|
|
|
|
|
Type.prototype = prototype;
|
|
|
|
|
return new Type();
|
|
|
|
|
};
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var object_keys = Object.keys || function (object) {
|
|
|
|
|
var keys = [];
|
|
|
|
|
for (var key in object) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (object_hasOwnProperty(object, key)) {
|
|
|
|
|
keys.push(key);
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
return keys;
|
|
|
|
|
};
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var object_toString = uncurryThis(Object.prototype.toString);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
// generator related shims
|
|
|
|
|
|
|
|
|
|
function isStopIteration(exception) {
|
|
|
|
|
return (
|
|
|
|
|
object_toString(exception) === "[object StopIteration]" ||
|
|
|
|
|
exception instanceof QReturnValue
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var QReturnValue;
|
|
|
|
|
if (typeof ReturnValue !== "undefined") {
|
|
|
|
|
QReturnValue = ReturnValue;
|
|
|
|
|
} else {
|
|
|
|
|
QReturnValue = function (value) {
|
|
|
|
|
this.value = value;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// long stack traces
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.longStackJumpLimit = 1;
|
|
|
|
|
|
|
|
|
|
var STACK_JUMP_SEPARATOR = "From previous event:";
|
|
|
|
|
|
|
|
|
|
function makeStackTraceLong(error, promise) {
|
|
|
|
|
// If possible (that is, if in V8), transform the error stack
|
|
|
|
|
// trace by removing Node and Q cruft, then concatenating with
|
|
|
|
|
// the stack trace of the promise we are ``done``ing. See #57.
|
|
|
|
|
if (promise.stack &&
|
|
|
|
|
typeof error === "object" &&
|
|
|
|
|
error !== null &&
|
|
|
|
|
error.stack &&
|
|
|
|
|
error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
|
|
|
|
|
) {
|
|
|
|
|
error.stack = filterStackString(error.stack) +
|
|
|
|
|
"\n" + STACK_JUMP_SEPARATOR + "\n" +
|
|
|
|
|
filterStackString(promise.stack);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
function filterStackString(stackString) {
|
|
|
|
|
var lines = stackString.split("\n");
|
|
|
|
|
var desiredLines = [];
|
|
|
|
|
for (var i = 0; i < lines.length; ++i) {
|
|
|
|
|
var line = lines[i];
|
|
|
|
|
|
|
|
|
|
if (!isInternalFrame(line) && !isNodeFrame(line)) {
|
|
|
|
|
desiredLines.push(line);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return desiredLines.join("\n");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
function isNodeFrame(stackLine) {
|
|
|
|
|
return stackLine.indexOf("(module.js:") !== -1 ||
|
|
|
|
|
stackLine.indexOf("(node.js:") !== -1;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
function isInternalFrame(stackLine) {
|
|
|
|
|
var pieces = /at .+ \((.*):(\d+):\d+\)/.exec(stackLine);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (!pieces) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var fileName = pieces[1];
|
|
|
|
|
var lineNumber = pieces[2];
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return fileName === qFileName &&
|
|
|
|
|
lineNumber >= qStartingLine &&
|
|
|
|
|
lineNumber <= qEndingLine;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
// discover own file name and line number range for filtering stack
|
|
|
|
|
// traces
|
|
|
|
|
function captureLine() {
|
|
|
|
|
if (Error.captureStackTrace) {
|
|
|
|
|
var fileName, lineNumber;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
var oldPrepareStackTrace = Error.prepareStackTrace;
|
|
|
|
|
|
|
|
|
|
Error.prepareStackTrace = function (error, frames) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
fileName = frames[1].getFileName();
|
|
|
|
|
lineNumber = frames[1].getLineNumber();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// teases call of temporary prepareStackTrace
|
|
|
|
|
// JSHint and Closure Compiler generate known warnings here
|
|
|
|
|
/*jshint expr: true */
|
|
|
|
|
new Error().stack;
|
|
|
|
|
|
|
|
|
|
Error.prepareStackTrace = oldPrepareStackTrace;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
qFileName = fileName;
|
|
|
|
|
return lineNumber;
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function deprecate(callback, name, alternative) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return function () {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
|
|
|
console.warn(name + " is deprecated, use " + alternative + " instead.", new Error("").stack);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
2012-12-11 08:22:26 +00:00
|
|
|
|
return callback.apply(callback, arguments);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// end of shims
|
|
|
|
|
// beginning of real work
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
/**
|
|
|
|
|
* Creates fulfilled promises from non-promises,
|
|
|
|
|
* Passes Q promises through,
|
|
|
|
|
* Coerces CommonJS/Promises/A+ promises to Q promises.
|
|
|
|
|
*/
|
|
|
|
|
function Q(value) {
|
|
|
|
|
return resolve(value);
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Performs a task in a future turn of the event loop.
|
|
|
|
|
* @param {Function} task
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nextTick = nextTick;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a {promise, resolve} object.
|
|
|
|
|
*
|
|
|
|
|
* The resolver is a callback to invoke with a more resolved value for the
|
|
|
|
|
* promise. To fulfill the promise, invoke the resolver with any value that is
|
|
|
|
|
* not a function. To reject the promise, invoke the resolver with a rejection
|
|
|
|
|
* object. To put the promise in the same state as another promise, invoke the
|
|
|
|
|
* resolver with that other promise.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.defer = defer;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function defer() {
|
|
|
|
|
// if "pending" is an "Array", that indicates that the promise has not yet
|
|
|
|
|
// been resolved. If it is "undefined", it has been resolved. Each
|
|
|
|
|
// element of the pending array is itself an array of complete arguments to
|
|
|
|
|
// forward to the resolved promise. We coerce the resolution value to a
|
|
|
|
|
// promise using the ref promise because it handles both fully
|
|
|
|
|
// resolved values and other promises gracefully.
|
2012-12-11 08:22:26 +00:00
|
|
|
|
var pending = [], progressListeners = [], value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
var deferred = object_create(defer.prototype);
|
|
|
|
|
var promise = object_create(makePromise.prototype);
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
promise.promiseDispatch = function (resolve, op, operands) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var args = array_slice(arguments);
|
|
|
|
|
if (pending) {
|
|
|
|
|
pending.push(args);
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (op === "when" && operands[1]) { // progress operand
|
|
|
|
|
progressListeners.push(operands[1]);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
} else {
|
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
value.promiseDispatch.apply(value, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
promise.valueOf = function () {
|
|
|
|
|
if (pending) {
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
value = valueOf(value); // shorten chain
|
|
|
|
|
return value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (Error.captureStackTrace && Q.longStackJumpLimit > 0) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
Error.captureStackTrace(promise, defer);
|
2013-02-17 03:43:39 +00:00
|
|
|
|
|
|
|
|
|
// Reify the stack into a string by using the accessor; this prevents
|
|
|
|
|
// memory leaks as per GH-111. At the same time, cut off the first line;
|
|
|
|
|
// it's always just "[object Promise]\n", as per the `toString`.
|
|
|
|
|
promise.stack = promise.stack.substring(promise.stack.indexOf("\n") + 1);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function become(resolvedValue) {
|
|
|
|
|
if (!pending) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
value = resolve(resolvedValue);
|
|
|
|
|
array_reduce(pending, function (undefined, pending) {
|
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
value.promiseDispatch.apply(value, pending);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
|
|
|
|
}, void 0);
|
|
|
|
|
pending = void 0;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
progressListeners = void 0;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deferred.promise = promise;
|
|
|
|
|
deferred.resolve = become;
|
2013-02-17 03:43:39 +00:00
|
|
|
|
deferred.fulfill = function (value) {
|
|
|
|
|
become(fulfill(value));
|
|
|
|
|
};
|
2012-06-03 04:43:42 +00:00
|
|
|
|
deferred.reject = function (exception) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
become(reject(exception));
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
2013-02-17 03:43:39 +00:00
|
|
|
|
deferred.notify = function (progress) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
if (pending) {
|
|
|
|
|
array_reduce(progressListeners, function (undefined, progressListener) {
|
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
progressListener(progress);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
});
|
|
|
|
|
}, void 0);
|
|
|
|
|
}
|
|
|
|
|
};
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
return deferred;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a Node-style callback that will resolve or reject the deferred
|
|
|
|
|
* promise.
|
|
|
|
|
* @returns a nodeback
|
|
|
|
|
*/
|
|
|
|
|
defer.prototype.makeNodeResolver = function () {
|
|
|
|
|
var self = this;
|
|
|
|
|
return function (error, value) {
|
|
|
|
|
if (error) {
|
|
|
|
|
self.reject(error);
|
|
|
|
|
} else if (arguments.length > 2) {
|
|
|
|
|
self.resolve(array_slice(arguments, 1));
|
|
|
|
|
} else {
|
|
|
|
|
self.resolve(value);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param makePromise {Function} a function that returns nothing and accepts
|
2012-12-11 08:22:26 +00:00
|
|
|
|
* the resolve, reject, and notify functions for a deferred.
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* @returns a promise that may be resolved with the given resolve and reject
|
|
|
|
|
* functions, or rejected by a thrown exception in makePromise
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.promise = promise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function promise(makePromise) {
|
|
|
|
|
var deferred = defer();
|
2012-12-11 08:22:26 +00:00
|
|
|
|
fcall(
|
2012-06-03 04:43:42 +00:00
|
|
|
|
makePromise,
|
|
|
|
|
deferred.resolve,
|
2012-12-11 08:22:26 +00:00
|
|
|
|
deferred.reject,
|
|
|
|
|
deferred.notify
|
2012-06-03 04:43:42 +00:00
|
|
|
|
).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a Promise with a promise descriptor object and optional fallback
|
|
|
|
|
* function. The descriptor contains methods like when(rejected), get(name),
|
|
|
|
|
* put(name, value), post(name, args), and delete(name), which all
|
|
|
|
|
* return either a value, a promise for a value, or a rejection. The fallback
|
|
|
|
|
* accepts the operation name, a resolver, and any further arguments that would
|
|
|
|
|
* have been forwarded to the appropriate method above had a method been
|
|
|
|
|
* provided with the proper name. The API makes no guarantees about the nature
|
|
|
|
|
* of the returned object, apart from that it is usable whereever promises are
|
|
|
|
|
* bought and sold.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.makePromise = makePromise;
|
|
|
|
|
function makePromise(descriptor, fallback, valueOf, exception, isException) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
if (fallback === void 0) {
|
|
|
|
|
fallback = function (op) {
|
|
|
|
|
return reject(new Error("Promise does not support operation: " + op));
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var promise = object_create(makePromise.prototype);
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
promise.promiseDispatch = function (resolve, op, args) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var result;
|
|
|
|
|
try {
|
|
|
|
|
if (descriptor[op]) {
|
|
|
|
|
result = descriptor[op].apply(promise, args);
|
|
|
|
|
} else {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
result = fallback.call(promise, op, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
} catch (exception) {
|
|
|
|
|
result = reject(exception);
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (resolve) {
|
|
|
|
|
resolve(result);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (valueOf) {
|
|
|
|
|
promise.valueOf = valueOf;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (isException) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
promise.exception = exception;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// provide thenables, CommonJS/Promises/A
|
2012-12-11 08:22:26 +00:00
|
|
|
|
makePromise.prototype.then = function (fulfilled, rejected, progressed) {
|
|
|
|
|
return when(this, fulfilled, rejected, progressed);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
makePromise.prototype.thenResolve = function (value) {
|
|
|
|
|
return when(this, function () { return value; });
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Chainable methods
|
|
|
|
|
array_reduce(
|
|
|
|
|
[
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"isFulfilled", "isRejected", "isPending",
|
|
|
|
|
"dispatch",
|
|
|
|
|
"when", "spread",
|
|
|
|
|
"get", "put", "set", "del", "delete",
|
2013-03-28 23:13:02 +00:00
|
|
|
|
// .send() disabled by Zotero for Mozilla Task.jsm compatibility
|
|
|
|
|
//"post", "send", "invoke",
|
|
|
|
|
"post", "invoke",
|
2012-06-03 04:43:42 +00:00
|
|
|
|
"keys",
|
|
|
|
|
"fapply", "fcall", "fbind",
|
|
|
|
|
"all", "allResolved",
|
|
|
|
|
"timeout", "delay",
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"catch", "finally", "fail", "fin", "progress", "done",
|
|
|
|
|
"nfcall", "nfapply", "nfbind", "denodeify", "nbind",
|
2012-12-11 08:22:26 +00:00
|
|
|
|
"ncall", "napply", "nbind",
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"npost", "nsend", "ninvoke",
|
|
|
|
|
"nodeify"
|
2012-06-03 04:43:42 +00:00
|
|
|
|
],
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function (undefined, name) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
makePromise.prototype[name] = function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return Q[name].apply(
|
|
|
|
|
Q,
|
2012-06-03 04:43:42 +00:00
|
|
|
|
[this].concat(array_slice(arguments))
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
void 0
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
makePromise.prototype.toSource = function () {
|
|
|
|
|
return this.toString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
makePromise.prototype.toString = function () {
|
|
|
|
|
return "[object Promise]";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If an object is not a promise, it is as "near" as possible.
|
|
|
|
|
* If a promise is rejected, it is as "near" as possible too.
|
|
|
|
|
* If it’s a fulfilled promise, the fulfillment value is nearer.
|
|
|
|
|
* If it’s a deferred promise and the deferred has been resolved, the
|
|
|
|
|
* resolution is "nearer".
|
|
|
|
|
* @param object
|
|
|
|
|
* @returns most resolved (nearest) form of the object
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nearer = valueOf;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function valueOf(value) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (isPromise(value)) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return value.valueOf();
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @returns whether the given object is a promise.
|
|
|
|
|
* Otherwise it is a fulfilled value.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.isPromise = isPromise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function isPromise(object) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return object && typeof object.promiseDispatch === "function";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q.isPromiseAlike = isPromiseAlike;
|
|
|
|
|
function isPromiseAlike(object) {
|
|
|
|
|
return object && typeof object.then === "function";
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* @returns whether the given object is a pending promise, meaning not
|
|
|
|
|
* fulfilled or rejected.
|
2012-06-03 04:43:42 +00:00
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.isPending = isPending;
|
|
|
|
|
function isPending(object) {
|
|
|
|
|
return !isFulfilled(object) && !isRejected(object);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @returns whether the given object is a value or fulfilled
|
|
|
|
|
* promise.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.isFulfilled = isFulfilled;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function isFulfilled(object) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return !isPromiseAlike(valueOf(object));
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @returns whether the given object is a rejected promise.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.isRejected = isRejected;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function isRejected(object) {
|
|
|
|
|
object = valueOf(object);
|
|
|
|
|
return isPromise(object) && 'exception' in object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rejections = [];
|
|
|
|
|
var errors = [];
|
2012-12-11 08:22:26 +00:00
|
|
|
|
var errorsDisplayed;
|
|
|
|
|
function displayErrors() {
|
|
|
|
|
if (
|
|
|
|
|
!errorsDisplayed &&
|
|
|
|
|
typeof window !== "undefined" &&
|
|
|
|
|
!window.Touch &&
|
|
|
|
|
window.console
|
|
|
|
|
) {
|
|
|
|
|
// This promise library consumes exceptions thrown in handlers so
|
|
|
|
|
// they can be handled by a subsequent promise. The rejected
|
|
|
|
|
// promises get added to this array when they are created, and
|
|
|
|
|
// removed when they are handled.
|
|
|
|
|
console.log("Should be empty:", errors);
|
|
|
|
|
}
|
|
|
|
|
errorsDisplayed = true;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
// Show unhandled rejection if Node exits without handling an outstanding
|
|
|
|
|
// rejection. (Note that Browserify presently produces a process global
|
|
|
|
|
// without the Emitter on interface)
|
|
|
|
|
if (typeof process !== "undefined" && process.on) {
|
|
|
|
|
process.on("exit", function () {
|
|
|
|
|
for (var i = 0; i < errors.length; i++) {
|
|
|
|
|
var error = errors[i];
|
|
|
|
|
if (error && typeof error.stack !== "undefined") {
|
|
|
|
|
console.warn("Unhandled rejected promise:", error.stack);
|
|
|
|
|
} else {
|
|
|
|
|
console.warn("Unhandled rejected promise (no stack):", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a rejected promise.
|
|
|
|
|
* @param exception value describing the failure
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.reject = reject;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function reject(exception) {
|
|
|
|
|
var rejection = makePromise({
|
|
|
|
|
"when": function (rejected) {
|
|
|
|
|
// note that the error has been handled
|
|
|
|
|
if (rejected) {
|
|
|
|
|
var at = array_indexOf(rejections, this);
|
|
|
|
|
if (at !== -1) {
|
|
|
|
|
errors.splice(at, 1);
|
|
|
|
|
rejections.splice(at, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return rejected ? rejected(exception) : this;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
2012-12-11 08:22:26 +00:00
|
|
|
|
}, function fallback() {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return reject(exception);
|
|
|
|
|
}, function valueOf() {
|
|
|
|
|
return this;
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}, exception, true);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
// note that the error has not been handled
|
2012-12-11 08:22:26 +00:00
|
|
|
|
displayErrors();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
rejections.push(rejection);
|
|
|
|
|
errors.push(exception);
|
|
|
|
|
return rejection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Constructs a fulfilled promise for an immediate reference.
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* @param value immediate reference
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.fulfill = fulfill;
|
|
|
|
|
function fulfill(object) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return makePromise({
|
2012-12-11 08:22:26 +00:00
|
|
|
|
"when": function () {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return object;
|
|
|
|
|
},
|
|
|
|
|
"get": function (name) {
|
|
|
|
|
return object[name];
|
|
|
|
|
},
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"set": function (name, value) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
object[name] = value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
},
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"delete": function (name) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
delete object[name];
|
2012-06-03 04:43:42 +00:00
|
|
|
|
},
|
2013-02-17 03:43:39 +00:00
|
|
|
|
"post": function (name, args) {
|
|
|
|
|
// Mark Miller proposes that post with no name should apply a
|
|
|
|
|
// promised function.
|
|
|
|
|
if (name == null) { // iff name is null or undefined
|
|
|
|
|
return object.apply(void 0, args);
|
|
|
|
|
} else {
|
|
|
|
|
return object[name].apply(object, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
},
|
|
|
|
|
"apply": function (thisP, args) {
|
|
|
|
|
return object.apply(thisP, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
},
|
|
|
|
|
"keys": function () {
|
|
|
|
|
return object_keys(object);
|
|
|
|
|
}
|
|
|
|
|
}, void 0, function valueOf() {
|
|
|
|
|
return object;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a promise for an immediate reference, passes promises through, or
|
|
|
|
|
* coerces promises from different systems.
|
|
|
|
|
* @param value immediate reference or promise
|
|
|
|
|
*/
|
|
|
|
|
Q.resolve = resolve;
|
|
|
|
|
function resolve(value) {
|
|
|
|
|
// If the object is already a Promise, return it directly. This enables
|
|
|
|
|
// the resolve function to both be used to created references from objects,
|
|
|
|
|
// but to tolerably coerce non-promises to promises.
|
|
|
|
|
if (isPromise(value)) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
// In order to break infinite recursion or loops between `then` and
|
|
|
|
|
// `resolve`, it is necessary to attempt to extract fulfilled values
|
|
|
|
|
// out of foreign promise implementations before attempting to wrap
|
|
|
|
|
// them as unresolved promises. It is my hope that other
|
|
|
|
|
// implementations will implement `valueOf` to synchronously extract
|
|
|
|
|
// the fulfillment value from their fulfilled promises. If the
|
|
|
|
|
// other promise library does not implement `valueOf`, the
|
|
|
|
|
// implementations on primordial prototypes are harmless.
|
|
|
|
|
value = valueOf(value);
|
|
|
|
|
// assimilate thenables, CommonJS/Promises/A+
|
|
|
|
|
if (isPromiseAlike(value)) {
|
|
|
|
|
return coerce(value);
|
|
|
|
|
} else {
|
|
|
|
|
return fulfill(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts thenables to Q promises.
|
|
|
|
|
* @param promise thenable promise
|
|
|
|
|
* @returns a Q promise
|
|
|
|
|
*/
|
|
|
|
|
function coerce(promise) {
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nextTick(function () {
|
|
|
|
|
try {
|
|
|
|
|
promise.then(deferred.resolve, deferred.reject, deferred.notify);
|
|
|
|
|
} catch (exception) {
|
|
|
|
|
deferred.reject(exception);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Annotates an object such that it will never be
|
|
|
|
|
* transferred away from this process over any promise
|
|
|
|
|
* communication channel.
|
|
|
|
|
* @param object
|
|
|
|
|
* @returns promise a wrapping of that object that
|
|
|
|
|
* additionally responds to the "isDef" message
|
|
|
|
|
* without a rejection.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.master = master;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function master(object) {
|
|
|
|
|
return makePromise({
|
|
|
|
|
"isDef": function () {}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}, function fallback(op, args) {
|
|
|
|
|
return dispatch(object, op, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}, function () {
|
|
|
|
|
return valueOf(object);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Registers an observer on a promise.
|
|
|
|
|
*
|
|
|
|
|
* Guarantees:
|
|
|
|
|
*
|
|
|
|
|
* 1. that fulfilled and rejected will be called only once.
|
|
|
|
|
* 2. that either the fulfilled callback or the rejected callback will be
|
|
|
|
|
* called, but not both.
|
|
|
|
|
* 3. that fulfilled and rejected will not be called in this turn.
|
|
|
|
|
*
|
2012-12-11 08:22:26 +00:00
|
|
|
|
* @param value promise or immediate reference to observe
|
|
|
|
|
* @param fulfilled function to be called with the fulfilled value
|
|
|
|
|
* @param rejected function to be called with the rejection exception
|
|
|
|
|
* @param progressed function to be called on any progress notifications
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* @return promise for the return value from the invoked callback
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.when = when;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function when(value, fulfilled, rejected, progressed) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var deferred = defer();
|
|
|
|
|
var done = false; // ensure the untrusted promise makes at most a
|
|
|
|
|
// single call to one of the callbacks
|
|
|
|
|
|
|
|
|
|
function _fulfilled(value) {
|
|
|
|
|
try {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return typeof fulfilled === "function" ? fulfilled(value) : value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
} catch (exception) {
|
|
|
|
|
return reject(exception);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _rejected(exception) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (typeof rejected === "function") {
|
|
|
|
|
makeStackTraceLong(exception, resolvedValue);
|
|
|
|
|
try {
|
|
|
|
|
return rejected(exception);
|
|
|
|
|
} catch (newException) {
|
|
|
|
|
return reject(newException);
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return reject(exception);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _progressed(value) {
|
|
|
|
|
return typeof progressed === "function" ? progressed(value) : value;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
var resolvedValue = resolve(value);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
resolvedValue.promiseDispatch(function (value) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
if (done) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
done = true;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
|
|
|
|
|
deferred.resolve(_fulfilled(value));
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}, "when", [function (exception) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
if (done) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
done = true;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
deferred.resolve(_rejected(exception));
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}]);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
// Progress propagator need to be attached in the current tick.
|
|
|
|
|
resolvedValue.promiseDispatch(void 0, "when", [void 0, function (value) {
|
|
|
|
|
var newValue;
|
|
|
|
|
var threw = false;
|
|
|
|
|
try {
|
|
|
|
|
newValue = _progressed(value);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
threw = true;
|
|
|
|
|
if (Q.onerror) {
|
|
|
|
|
Q.onerror(e);
|
|
|
|
|
} else {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!threw) {
|
|
|
|
|
deferred.notify(newValue);
|
|
|
|
|
}
|
|
|
|
|
}]);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Spreads the values of a promised array of arguments into the
|
|
|
|
|
* fulfillment callback.
|
|
|
|
|
* @param fulfilled callback that receives variadic arguments from the
|
|
|
|
|
* promised array
|
|
|
|
|
* @param rejected callback that receives the exception if the promise
|
|
|
|
|
* is rejected.
|
|
|
|
|
* @returns a promise for the return value or thrown exception of
|
|
|
|
|
* either callback.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.spread = spread;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function spread(promise, fulfilled, rejected) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
return when(promise, function (valuesOrPromises) {
|
|
|
|
|
return all(valuesOrPromises).then(function (values) {
|
|
|
|
|
return fulfilled.apply(void 0, values);
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}, rejected);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}, rejected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The async function is a decorator for generator functions, turning
|
|
|
|
|
* them into asynchronous generators. This presently only works in
|
|
|
|
|
* Firefox/Spidermonkey, however, this code does not cause syntax
|
|
|
|
|
* errors in older engines. This code should continue to work and
|
|
|
|
|
* will in fact improve over time as the language improves.
|
|
|
|
|
*
|
|
|
|
|
* Decorates a generator function such that:
|
|
|
|
|
* - it may yield promises
|
|
|
|
|
* - execution will continue when that promise is fulfilled
|
|
|
|
|
* - the value of the yield expression will be the fulfilled value
|
|
|
|
|
* - it returns a promise for the return value (when the generator
|
|
|
|
|
* stops iterating)
|
|
|
|
|
* - the decorated function returns a promise for the return value
|
|
|
|
|
* of the generator or the first rejected promise among those
|
|
|
|
|
* yielded.
|
|
|
|
|
* - if an error is thrown in the generator, it propagates through
|
|
|
|
|
* every following yield until it is caught, or until it escapes
|
|
|
|
|
* the generator function altogether, and is translated into a
|
|
|
|
|
* rejection for the promise returned by the decorated generator.
|
|
|
|
|
* - in present implementations of generators, when a generator
|
|
|
|
|
* function is complete, it throws ``StopIteration``, ``return`` is
|
|
|
|
|
* a syntax error in the presence of ``yield``, so there is no
|
|
|
|
|
* observable return value. There is a proposal[1] to add support
|
|
|
|
|
* for ``return``, which would permit the value to be carried by a
|
|
|
|
|
* ``StopIteration`` instance, in which case it would fulfill the
|
|
|
|
|
* promise returned by the asynchronous generator. This can be
|
|
|
|
|
* emulated today by throwing StopIteration explicitly with a value
|
|
|
|
|
* property.
|
|
|
|
|
*
|
|
|
|
|
* [1]: http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation
|
|
|
|
|
*
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.async = async;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function async(makeGenerator) {
|
|
|
|
|
return function () {
|
|
|
|
|
// when verb is "send", arg is a value
|
|
|
|
|
// when verb is "throw", arg is an exception
|
|
|
|
|
function continuer(verb, arg) {
|
|
|
|
|
var result;
|
|
|
|
|
try {
|
|
|
|
|
result = generator[verb](arg);
|
|
|
|
|
} catch (exception) {
|
|
|
|
|
if (isStopIteration(exception)) {
|
|
|
|
|
return exception.value;
|
|
|
|
|
} else {
|
|
|
|
|
return reject(exception);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return when(result, callback, errback);
|
|
|
|
|
}
|
2014-06-20 07:20:35 +00:00
|
|
|
|
// Added by Dan
|
|
|
|
|
// If already a generator, use that
|
|
|
|
|
if (makeGenerator.send) {
|
|
|
|
|
var generator = makeGenerator;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
var generator = makeGenerator.apply(this, arguments);
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var callback = continuer.bind(continuer, "send");
|
|
|
|
|
var errback = continuer.bind(continuer, "throw");
|
|
|
|
|
return callback();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Throws a ReturnValue exception to stop an asynchronous generator.
|
|
|
|
|
* Only useful presently in Firefox/SpiderMonkey since generators are
|
|
|
|
|
* implemented.
|
|
|
|
|
* @param value the return value for the surrounding generator
|
|
|
|
|
* @throws ReturnValue exception with the value.
|
|
|
|
|
* @example
|
|
|
|
|
* Q.async(function () {
|
|
|
|
|
* var foo = yield getFooPromise();
|
|
|
|
|
* var bar = yield getBarPromise();
|
|
|
|
|
* Q.return(foo + bar);
|
|
|
|
|
* })
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q['return'] = _return;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function _return(value) {
|
|
|
|
|
throw new QReturnValue(value);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* The promised function decorator ensures that any promise arguments
|
|
|
|
|
* are resolved and passed as values (`this` is also resolved and passed
|
|
|
|
|
* as a value). It will also ensure that the result of a function is
|
|
|
|
|
* always a promise.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* var add = Q.promised(function (a, b) {
|
|
|
|
|
* return a + b;
|
|
|
|
|
* });
|
|
|
|
|
* add(Q.resolve(a), Q.resolve(B));
|
|
|
|
|
*
|
|
|
|
|
* @param {function} callback The function to decorate
|
|
|
|
|
* @returns {function} a function that has been decorated.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.promised = promised;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function promised(callback) {
|
|
|
|
|
return function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return spread([this, all(arguments)], function (self, args) {
|
|
|
|
|
return callback.apply(self, args);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* sends a message to a value in a future turn
|
|
|
|
|
* @param object* the recipient
|
|
|
|
|
* @param op the name of the message operation, e.g., "when",
|
|
|
|
|
* @param args further arguments to be forwarded to the operation
|
|
|
|
|
* @returns result {Promise} a promise for the result of the operation
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.dispatch = dispatch;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function dispatch(object, op, args) {
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
resolve(object).promiseDispatch(deferred.resolve, op, args);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a promise method that can be used to safely observe resolution of
|
|
|
|
|
* a promise for an arbitrarily named method like "propfind" in a future turn.
|
|
|
|
|
*
|
|
|
|
|
* "dispatcher" constructs methods like "get(promise, name)" and "put(promise)".
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.dispatcher = dispatcher;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function dispatcher(op) {
|
|
|
|
|
return function (object) {
|
|
|
|
|
var args = array_slice(arguments, 1);
|
|
|
|
|
return dispatch(object, op, args);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the value of a property in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target object
|
|
|
|
|
* @param name name of property to get
|
|
|
|
|
* @return promise for the property value
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.get = dispatcher("get");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the value of a property in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for object object
|
|
|
|
|
* @param name name of property to set
|
|
|
|
|
* @param value new value of property
|
|
|
|
|
* @return promise for the return value
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.set = dispatcher("set");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Deletes a property in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target object
|
|
|
|
|
* @param name name of property to delete
|
|
|
|
|
* @return promise for the return value
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q["delete"] = // XXX experimental
|
|
|
|
|
Q.del = dispatcher("delete");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invokes a method in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target object
|
|
|
|
|
* @param name name of method to invoke
|
|
|
|
|
* @param value a value to post, typically an array of
|
|
|
|
|
* invocation arguments for promises that
|
|
|
|
|
* are ultimately backed with `resolve` values,
|
|
|
|
|
* as opposed to those backed with URLs
|
|
|
|
|
* wherein the posted value can be any
|
|
|
|
|
* JSON serializable object.
|
|
|
|
|
* @return promise for the return value
|
|
|
|
|
*/
|
|
|
|
|
// bound locally because it is used by other methods
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var post = Q.post = dispatcher("post");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invokes a method in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target object
|
|
|
|
|
* @param name name of method to invoke
|
|
|
|
|
* @param ...args array of invocation arguments
|
|
|
|
|
* @return promise for the return value
|
|
|
|
|
*/
|
2013-03-28 23:13:02 +00:00
|
|
|
|
// Disabled by Zotero for Mozilla Task.jsm compatibility
|
|
|
|
|
//Q.send = send;
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.invoke = send; // synonyms
|
|
|
|
|
function send(value, name) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var args = array_slice(arguments, 2);
|
|
|
|
|
return post(value, name, args);
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Applies the promised function in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target function
|
|
|
|
|
* @param args array of application arguments
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.fapply = fapply;
|
|
|
|
|
function fapply(value, args) {
|
|
|
|
|
return dispatch(value, "apply", [void 0, args]);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calls the promised function in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target function
|
|
|
|
|
* @param ...args array of application arguments
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q["try"] = fcall; // XXX experimental
|
|
|
|
|
Q.fcall = fcall;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function fcall(value) {
|
|
|
|
|
var args = array_slice(arguments, 1);
|
|
|
|
|
return fapply(value, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Binds the promised function, transforming return values into a fulfilled
|
|
|
|
|
* promise and thrown errors into a rejected one.
|
|
|
|
|
* @param object promise or immediate reference for target function
|
|
|
|
|
* @param ...args array of application arguments
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.fbind = fbind;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function fbind(value) {
|
|
|
|
|
var args = array_slice(arguments, 1);
|
|
|
|
|
return function fbound() {
|
|
|
|
|
var allArgs = args.concat(array_slice(arguments));
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return dispatch(value, "apply", [this, allArgs]);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Requests the names of the owned properties of a promised
|
|
|
|
|
* object in a future turn.
|
|
|
|
|
* @param object promise or immediate reference for target object
|
|
|
|
|
* @return promise for the keys of the eventually resolved object
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.keys = dispatcher("keys");
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Turns an array of promises into a promise for an array. If any of
|
|
|
|
|
* the promises gets rejected, the whole array is rejected immediately.
|
|
|
|
|
* @param {Array*} an array (or promise for an array) of values (or
|
|
|
|
|
* promises for values)
|
|
|
|
|
* @returns a promise for an array of the corresponding values
|
|
|
|
|
*/
|
|
|
|
|
// By Mark Miller
|
|
|
|
|
// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.all = all;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function all(promises) {
|
|
|
|
|
return when(promises, function (promises) {
|
|
|
|
|
var countDown = promises.length;
|
|
|
|
|
if (countDown === 0) {
|
|
|
|
|
return resolve(promises);
|
|
|
|
|
}
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
array_reduce(promises, function (undefined, promise, index) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
if (isFulfilled(promise)) {
|
|
|
|
|
promises[index] = valueOf(promise);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
if (--countDown === 0) {
|
|
|
|
|
deferred.resolve(promises);
|
|
|
|
|
}
|
2012-12-11 08:22:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
when(promise, function (value) {
|
|
|
|
|
promises[index] = value;
|
|
|
|
|
if (--countDown === 0) {
|
|
|
|
|
deferred.resolve(promises);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.fail(deferred.reject);
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}, void 0);
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Waits for all promises to be resolved, either fulfilled or
|
|
|
|
|
* rejected. This is distinct from `all` since that would stop
|
|
|
|
|
* waiting at the first rejection. The promise returned by
|
|
|
|
|
* `allResolved` will never be rejected.
|
|
|
|
|
* @param promises a promise for an array (or an array) of promises
|
|
|
|
|
* (or values)
|
|
|
|
|
* @return a promise for an array of promises
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.allResolved = allResolved;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function allResolved(promises) {
|
|
|
|
|
return when(promises, function (promises) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
promises = array_map(promises, resolve);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return when(all(array_map(promises, function (promise) {
|
|
|
|
|
return when(promise, noop, noop);
|
|
|
|
|
})), function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return promises;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Captures the failure of a promise, giving an oportunity to recover
|
|
|
|
|
* with a callback. If the given promise is fulfilled, the returned
|
|
|
|
|
* promise is fulfilled.
|
|
|
|
|
* @param {Any*} promise for something
|
|
|
|
|
* @param {Function} callback to fulfill the returned promise if the
|
|
|
|
|
* given promise is rejected
|
|
|
|
|
* @returns a promise for the return value of the callback
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q["catch"] = // XXX experimental
|
|
|
|
|
Q.fail = fail;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function fail(promise, rejected) {
|
|
|
|
|
return when(promise, void 0, rejected);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 08:22:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Attaches a listener that can respond to progress notifications from a
|
|
|
|
|
* promise's originating deferred. This listener receives the exact arguments
|
|
|
|
|
* passed to ``deferred.notify``.
|
|
|
|
|
* @param {Any*} promise for something
|
|
|
|
|
* @param {Function} callback to receive any progress notifications
|
|
|
|
|
* @returns the given promise, unchanged
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.progress = progress;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function progress(promise, progressed) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return when(promise, void 0, void 0, progressed);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Provides an opportunity to observe the rejection of a promise,
|
|
|
|
|
* regardless of whether the promise is fulfilled or rejected. Forwards
|
|
|
|
|
* the resolution to the returned promise when the callback is done.
|
|
|
|
|
* The callback can return a promise to defer completion.
|
|
|
|
|
* @param {Any*} promise
|
|
|
|
|
* @param {Function} callback to observe the resolution of the given
|
|
|
|
|
* promise, takes no arguments.
|
|
|
|
|
* @returns a promise for the resolution of the given promise when
|
|
|
|
|
* ``fin`` is done.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q["finally"] = // XXX experimental
|
|
|
|
|
Q.fin = fin;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function fin(promise, callback) {
|
|
|
|
|
return when(promise, function (value) {
|
|
|
|
|
return when(callback(), function () {
|
|
|
|
|
return value;
|
|
|
|
|
});
|
|
|
|
|
}, function (exception) {
|
|
|
|
|
return when(callback(), function () {
|
|
|
|
|
return reject(exception);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Terminates a chain of promises, forcing rejections to be
|
|
|
|
|
* thrown as exceptions.
|
|
|
|
|
* @param {Any*} promise at the end of a chain of promises
|
|
|
|
|
* @returns nothing
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.done = done;
|
2012-12-11 08:22:26 +00:00
|
|
|
|
function done(promise, fulfilled, rejected, progress) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var onUnhandledError = function (error) {
|
2012-06-03 04:43:42 +00:00
|
|
|
|
// forward to a future turn so that ``when``
|
|
|
|
|
// does not catch it and turn it into a rejection.
|
|
|
|
|
nextTick(function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
makeStackTraceLong(error, promise);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (Q.onerror) {
|
|
|
|
|
Q.onerror(error);
|
2012-12-11 08:22:26 +00:00
|
|
|
|
} else {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|
2013-02-17 03:43:39 +00:00
|
|
|
|
};
|
2012-12-11 08:22:26 +00:00
|
|
|
|
|
|
|
|
|
// Avoid unnecessary `nextTick`ing via an unnecessary `when`.
|
|
|
|
|
var promiseToHandle = fulfilled || rejected || progress ?
|
|
|
|
|
when(promise, fulfilled, rejected, progress) :
|
|
|
|
|
promise;
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
if (typeof process === "object" && process && process.domain) {
|
|
|
|
|
onUnhandledError = process.domain.bind(onUnhandledError);
|
|
|
|
|
}
|
2012-12-11 08:22:26 +00:00
|
|
|
|
fail(promiseToHandle, onUnhandledError);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Causes a promise to be rejected if it does not get fulfilled before
|
|
|
|
|
* some milliseconds time out.
|
|
|
|
|
* @param {Any*} promise
|
|
|
|
|
* @param {Number} milliseconds timeout
|
|
|
|
|
* @returns a promise for the resolution of the given promise if it is
|
|
|
|
|
* fulfilled before the timeout, otherwise rejected.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.timeout = timeout;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function timeout(promise, ms) {
|
|
|
|
|
var deferred = defer();
|
2012-07-10 01:01:29 +00:00
|
|
|
|
var timeoutId = setTimeout(function () {
|
|
|
|
|
deferred.reject(new Error("Timed out after " + ms + " ms"));
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}, ms);
|
2012-07-10 01:01:29 +00:00
|
|
|
|
|
|
|
|
|
when(promise, function (value) {
|
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
|
deferred.resolve(value);
|
2013-02-17 03:43:39 +00:00
|
|
|
|
}, function (exception) {
|
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
|
deferred.reject(exception);
|
|
|
|
|
});
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a promise for the given value (or promised value) after some
|
|
|
|
|
* milliseconds.
|
|
|
|
|
* @param {Any*} promise
|
|
|
|
|
* @param {Number} milliseconds
|
|
|
|
|
* @returns a promise for the resolution of the given promise after some
|
|
|
|
|
* time has elapsed.
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.delay = delay;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function delay(promise, timeout) {
|
|
|
|
|
if (timeout === void 0) {
|
|
|
|
|
timeout = promise;
|
|
|
|
|
promise = void 0;
|
|
|
|
|
}
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
deferred.resolve(promise);
|
|
|
|
|
}, timeout);
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Passes a continuation to a Node function, which is called with the given
|
|
|
|
|
* arguments provided as an array, and returns a promise.
|
2012-06-03 04:43:42 +00:00
|
|
|
|
*
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Q.nfapply(FS.readFile, [__filename])
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* .then(function (content) {
|
|
|
|
|
* })
|
|
|
|
|
*
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nfapply = nfapply;
|
|
|
|
|
function nfapply(callback, args) {
|
|
|
|
|
var nodeArgs = array_slice(args);
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
|
|
|
|
|
fapply(callback, nodeArgs).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Passes a continuation to a Node function, which is called with the given
|
|
|
|
|
* arguments provided individually, and returns a promise.
|
2012-06-03 04:43:42 +00:00
|
|
|
|
*
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Q.nfcall(FS.readFile, __filename)
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* .then(function (content) {
|
|
|
|
|
* })
|
|
|
|
|
*
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nfcall = nfcall;
|
|
|
|
|
function nfcall(callback/*, ...args */) {
|
|
|
|
|
var nodeArgs = array_slice(arguments, 1);
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
|
|
|
|
|
fapply(callback, nodeArgs).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wraps a NodeJS continuation passing function and returns an equivalent
|
|
|
|
|
* version that returns a promise.
|
|
|
|
|
*
|
2013-02-17 03:43:39 +00:00
|
|
|
|
* Q.nfbind(FS.readFile, __filename)("utf-8")
|
2012-06-03 04:43:42 +00:00
|
|
|
|
* .then(console.log)
|
2012-12-11 08:22:26 +00:00
|
|
|
|
* .done()
|
2012-06-03 04:43:42 +00:00
|
|
|
|
*
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nfbind = nfbind;
|
|
|
|
|
Q.denodeify = Q.nfbind; // synonyms
|
|
|
|
|
function nfbind(callback/*, ...args */) {
|
|
|
|
|
var baseArgs = array_slice(arguments, 1);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return function () {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var nodeArgs = baseArgs.concat(array_slice(arguments));
|
2012-06-03 04:43:42 +00:00
|
|
|
|
var deferred = defer();
|
2013-02-17 03:43:39 +00:00
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
|
|
|
|
|
fapply(callback, nodeArgs).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q.nbind = nbind;
|
|
|
|
|
function nbind(callback/*, ... args*/) {
|
|
|
|
|
var baseArgs = array_slice(arguments, 1);
|
|
|
|
|
return function () {
|
|
|
|
|
var nodeArgs = baseArgs.concat(array_slice(arguments));
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
|
|
|
|
|
var thisArg = this;
|
|
|
|
|
function bound() {
|
|
|
|
|
return callback.apply(thisArg, arguments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fapply(bound, nodeArgs).fail(deferred.reject);
|
2012-06-03 04:43:42 +00:00
|
|
|
|
return deferred.promise;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calls a method of a Node-style object that accepts a Node-style
|
|
|
|
|
* callback with a given array of arguments, plus a provided callback.
|
|
|
|
|
* @param object an object that has the named method
|
|
|
|
|
* @param {String} name name of the method of object
|
|
|
|
|
* @param {Array} args arguments to pass to the method; the callback
|
|
|
|
|
* will be provided by Q and appended to these arguments.
|
|
|
|
|
* @returns a promise for the value or error
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.npost = npost;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
function npost(object, name, args) {
|
2013-02-17 03:43:39 +00:00
|
|
|
|
var nodeArgs = array_slice(args || []);
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
|
|
|
|
|
post(object, name, nodeArgs).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calls a method of a Node-style object that accepts a Node-style
|
|
|
|
|
* callback, forwarding the given variadic arguments, plus a provided
|
|
|
|
|
* callback argument.
|
|
|
|
|
* @param object an object that has the named method
|
|
|
|
|
* @param {String} name name of the method of object
|
|
|
|
|
* @param ...args arguments to pass to the method; the callback will
|
|
|
|
|
* be provided by Q and appended to these arguments.
|
|
|
|
|
* @returns a promise for the value or error
|
|
|
|
|
*/
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nsend = nsend;
|
|
|
|
|
Q.ninvoke = Q.nsend; // synonyms
|
|
|
|
|
function nsend(object, name /*, ...args*/) {
|
|
|
|
|
var nodeArgs = array_slice(arguments, 2);
|
|
|
|
|
var deferred = defer();
|
|
|
|
|
nodeArgs.push(deferred.makeNodeResolver());
|
|
|
|
|
post(object, name, nodeArgs).fail(deferred.reject);
|
|
|
|
|
return deferred.promise;
|
2012-06-03 04:43:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
Q.nodeify = nodeify;
|
|
|
|
|
function nodeify(promise, nodeback) {
|
2012-12-11 08:22:26 +00:00
|
|
|
|
if (nodeback) {
|
|
|
|
|
promise.then(function (value) {
|
|
|
|
|
nextTick(function () {
|
|
|
|
|
nodeback(null, value);
|
|
|
|
|
});
|
|
|
|
|
}, function (error) {
|
|
|
|
|
nextTick(function () {
|
|
|
|
|
nodeback(error);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All code before this point will be filtered from stack traces.
|
|
|
|
|
var qEndingLine = captureLine();
|
2012-06-03 04:43:42 +00:00
|
|
|
|
|
2013-02-17 03:43:39 +00:00
|
|
|
|
return Q;
|
|
|
|
|
|
2012-06-03 04:43:42 +00:00
|
|
|
|
});
|