365 lines
13 KiB
JavaScript
365 lines
13 KiB
JavaScript
/**
|
|
* @generated SignedSource<<d169e3bbcd91c2e26877882e0d02f289>>
|
|
*
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
* !! This file is a check-in of a static_upstream project! !!
|
|
* !! !!
|
|
* !! You should not modify this file directly. Instead: !!
|
|
* !! 1) Use `fjs use-upstream` to temporarily replace this with !!
|
|
* !! the latest version from upstream. !!
|
|
* !! 2) Make your changes, test them, etc. !!
|
|
* !! 3) Use `fjs push-upstream` to copy your changes back to !!
|
|
* !! static_upstream. !!
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
*
|
|
* Copyright 2013-2014 Facebook, 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.
|
|
*
|
|
* @providesModule ES6Promise
|
|
*
|
|
* This module implements the minimum functionality necessary to comply
|
|
* with chapter 25.4 of the ES6 specification. Any extensions to Promise
|
|
* or Promise.prototype should be added in the Promise module.
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects
|
|
*/
|
|
|
|
module.exports = (function(global, undefined) {
|
|
'use strict';
|
|
|
|
var setImmediate = require('setImmediate');
|
|
|
|
// These are the possible values for slots(promise).state.
|
|
var PENDING_STATE = 'pending';
|
|
var FULFILLED_STATE = 'fulfilled';
|
|
var REJECTED_STATE = 'rejected';
|
|
|
|
// The ES6 specification makes heavy use of a notion of internal slots.
|
|
// Some of these slots are best implemented as closure variables, such
|
|
// as the alreadySettled variable in createResolvingFunctions, which
|
|
// corresponds to the resolve.[[AlreadyResolved]].value property in the
|
|
// specification. Other slots are best implemented as properties of a
|
|
// slots object attached to the host object by a pseudo-private
|
|
// property. The latter kind of slots may be accessed by passing the
|
|
// host object (such as a Promise or a resolve/reject function object)
|
|
// to the slots function; e.g., the slots(promise).state slot, which
|
|
// corresponds to promise.[[PromiseState]] in the specification.
|
|
var slotsKey = '__slots$' + Math.random().toString(36).slice(2);
|
|
function slots(obj) {
|
|
var result = obj[slotsKey];
|
|
if (!result) {
|
|
// In ES5+ environments, this property will be safely non-writable,
|
|
// non-configurable, and non-enumerable. This implementation does
|
|
// not logically rely on those niceties, however, so this code works
|
|
// just fine in pre-ES5 environments, too.
|
|
obj[slotsKey] = result = {};
|
|
if (Object.defineProperty) try {
|
|
Object.defineProperty(obj, slotsKey, { value: result });
|
|
} catch (definePropertyIsBrokenInIE8) {}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Reusable callback functions. The identify function is the default
|
|
// when onFulfilled is undefined or null, and the raise function is the
|
|
// default when onRejected is undefined or null.
|
|
function identity(x) { return x; }
|
|
function raise(x) { throw x; }
|
|
|
|
/**
|
|
* When the Promise function is called with argument executor, the
|
|
* following steps are taken:
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise
|
|
*
|
|
* The executor argument must be a function object. It is called for
|
|
* initiating and reporting completion of the possibly deferred action
|
|
* represented by this Promise object. The executor is called with two
|
|
* arguments: resolve and reject. These are functions that may be used
|
|
* by the executor function to report eventual completion or failure of
|
|
* the deferred computation. Returning from the executor function does
|
|
* not mean that the deferred action has been completed, but only that
|
|
* the request to eventually perform the deferred action has been
|
|
* accepted.
|
|
*
|
|
* The resolve function that is passed to an executor function accepts a
|
|
* single argument. The executor code may eventually call the resolve
|
|
* function to indicate that it wishes to resolve the associated Promise
|
|
* object. The argument passed to the resolve function represents the
|
|
* eventual value of the deferred action and can be either the actual
|
|
* fulfillment value or another Promise object which will provide the
|
|
* value if it is fullfilled.
|
|
*
|
|
* The reject function that is passed to an executor function accepts a
|
|
* single argument. The executor code may eventually call the reject
|
|
* function to indicate that the associated Promise is rejected and will
|
|
* never be fulfilled. The argument passed to the reject function is
|
|
* used as the rejection value of the promise. Typically it will be an
|
|
* Error object.
|
|
*
|
|
* When Promise is called as a function rather than as a constructor, it
|
|
* initializes its this value with the internal state necessary to
|
|
* support the Promise.prototype methods.
|
|
*
|
|
* The Promise constructor is designed to be subclassable. It may be
|
|
* used as the value in an extends clause of a class
|
|
* definition. Subclass constructors that intend to inherit the
|
|
* specified Promise behaviour must include a super call to Promise,
|
|
* e.g. by invoking Promise.call(this, executor).
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-constructor
|
|
*/
|
|
function Promise(executor) {
|
|
var promiseSlots = slots(this);
|
|
promiseSlots.state = PENDING_STATE;
|
|
promiseSlots.fulfillReactions = [];
|
|
promiseSlots.rejectReactions = [];
|
|
|
|
var resolvingFunctions = createResolvingFunctions(this);
|
|
var reject = resolvingFunctions.reject;
|
|
|
|
try {
|
|
executor(resolvingFunctions.resolve, reject);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
}
|
|
|
|
function createResolvingFunctions(promise) {
|
|
var alreadySettled = false;
|
|
|
|
return {
|
|
resolve: function(resolution) {
|
|
if (!alreadySettled) {
|
|
alreadySettled = true;
|
|
|
|
if (resolution === promise) {
|
|
return settlePromise(
|
|
promise,
|
|
REJECTED_STATE,
|
|
new TypeError('Cannot resolve promise with itself')
|
|
);
|
|
}
|
|
|
|
// To be treated as a Promise-like object, the resolution only
|
|
// needs to be an object with a callable .then method.
|
|
if (!resolution ||
|
|
typeof resolution !== "object" ||
|
|
typeof resolution.then !== "function") {
|
|
return settlePromise(promise, FULFILLED_STATE, resolution);
|
|
}
|
|
|
|
var resolvingFunctions = createResolvingFunctions(promise);
|
|
var reject = resolvingFunctions.reject;
|
|
|
|
try {
|
|
resolution.then(resolvingFunctions.resolve, reject);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
}
|
|
},
|
|
|
|
reject: function(reason) {
|
|
if (!alreadySettled) {
|
|
alreadySettled = true;
|
|
settlePromise(promise, REJECTED_STATE, reason);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// This function unifies the FulfillPromise and RejectPromise functions
|
|
// defined in the ES6 specification.
|
|
function settlePromise(promise, state, result) {
|
|
var promiseSlots = slots(promise);
|
|
if (promiseSlots.state !== PENDING_STATE) {
|
|
throw new Error('Settling a ' + promiseSlots.state + ' promise');
|
|
}
|
|
|
|
var reactions;
|
|
if (state === FULFILLED_STATE) {
|
|
reactions = promiseSlots.fulfillReactions;
|
|
} else if (state === REJECTED_STATE) {
|
|
reactions = promiseSlots.rejectReactions;
|
|
}
|
|
|
|
promiseSlots.result = result;
|
|
promiseSlots.fulfillReactions = undefined;
|
|
promiseSlots.rejectReactions = undefined;
|
|
promiseSlots.state = state;
|
|
|
|
var count = reactions.length;
|
|
count && setImmediate(function() {
|
|
for (var i = 0; i < count; ++i) {
|
|
reactions[i](promiseSlots.result);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* The Promise.all function returns a new promise which is fulfilled
|
|
* with an array of fulfillment values for the passed promises, or
|
|
* rejects with the reason of the first passed promise that rejects. It
|
|
* resoves all elements of the passed iterable to promises as it runs
|
|
* this algorithm.
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.all
|
|
*/
|
|
Promise.all = function(array) {
|
|
var Promise = this;
|
|
return new Promise(function(resolve, reject) {
|
|
var results = [];
|
|
var remaining = 0;
|
|
array.forEach(function(element, index) {
|
|
++remaining; // Array might be sparse.
|
|
Promise.resolve(element).then(function(result) {
|
|
if (!results.hasOwnProperty(index)) {
|
|
results[index] = result;
|
|
--remaining || resolve(results);
|
|
}
|
|
}, reject);
|
|
});
|
|
remaining || resolve(results);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* The Promise.race function returns a new promise which is settled in
|
|
* the same way as the first passed promise to settle. It resolves all
|
|
* elements of the passed iterable to promises as it runs this
|
|
* algorithm.
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.race
|
|
*/
|
|
Promise.race = function(array) {
|
|
var Promise = this;
|
|
return new Promise(function(resolve, reject) {
|
|
array.forEach(function(element) {
|
|
Promise.resolve(element).then(resolve, reject);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* The Promise.resolve function returns either a new promise resolved
|
|
* with the passed argument, or the argument itself if the argument a
|
|
* promise produced by this construtor.
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.resolve
|
|
*/
|
|
Promise.resolve = function(x) {
|
|
return x instanceof Promise && x.constructor === this
|
|
? x // Refuse to create promises for promises.
|
|
: new this(function(resolve) { resolve(x); });
|
|
};
|
|
|
|
/**
|
|
* The Promise.reject function returns a new promise rejected with the
|
|
* passed argument.
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.reject
|
|
*/
|
|
Promise.reject = function(r) {
|
|
return new this(function(_, reject) { reject(r); });
|
|
};
|
|
|
|
var Pp = Promise.prototype;
|
|
|
|
/**
|
|
* When the .then method is called with arguments onFulfilled and
|
|
* onRejected, the following steps are taken:
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.prototype.then
|
|
*/
|
|
Pp.then = function(onFulfilled, onRejected) {
|
|
var capabilityResolve;
|
|
var capabilityReject;
|
|
var capabilityPromise = new this.constructor(function(resolve, reject) {
|
|
capabilityResolve = resolve;
|
|
capabilityReject = reject;
|
|
});
|
|
|
|
if (typeof capabilityResolve !== "function") {
|
|
throw new TypeError('Uncallable Promise resolve function');
|
|
}
|
|
|
|
if (typeof capabilityReject !== "function") {
|
|
throw new TypeError('Uncallable Promise reject function');
|
|
}
|
|
|
|
if (onFulfilled === undefined || onFulfilled === null) {
|
|
onFulfilled = identity;
|
|
}
|
|
|
|
if (onRejected === undefined || onRejected === null) {
|
|
onRejected = raise;
|
|
}
|
|
|
|
var promiseSlots = slots(this);
|
|
var state = promiseSlots.state;
|
|
if (state === PENDING_STATE) {
|
|
promiseSlots.fulfillReactions.push(makeReaction(
|
|
capabilityResolve,
|
|
capabilityReject,
|
|
onFulfilled
|
|
));
|
|
|
|
promiseSlots.rejectReactions.push(makeReaction(
|
|
capabilityResolve,
|
|
capabilityReject,
|
|
onRejected
|
|
));
|
|
|
|
} else if (state === FULFILLED_STATE || state === REJECTED_STATE) {
|
|
setImmediate(makeReaction(
|
|
capabilityResolve,
|
|
capabilityReject,
|
|
state === FULFILLED_STATE ? onFulfilled : onRejected,
|
|
promiseSlots.result
|
|
));
|
|
}
|
|
|
|
return capabilityPromise;
|
|
};
|
|
|
|
function makeReaction(resolve, reject, handler, argument) {
|
|
var hasArgument = arguments.length > 3;
|
|
return function(result) {
|
|
try {
|
|
result = handler(hasArgument ? argument : result);
|
|
} catch (err) {
|
|
reject(err);
|
|
return;
|
|
}
|
|
resolve(result);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* When the .catch method is called with argument onRejected, the
|
|
* following steps are taken:
|
|
*
|
|
* people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.prototype.catch
|
|
*/
|
|
Pp['catch'] = function(onRejected) {
|
|
return this.then(undefined, onRejected);
|
|
};
|
|
|
|
Pp.toString = function() {
|
|
return '[object Promise]';
|
|
};
|
|
|
|
return Promise;
|
|
}(/* jslint evil: true */ Function('return this')()));
|