A Promise
object represents a value that may not be available yet.
A reference to an existing promise may be received by different means, for example as the return value of a call into an asynchronous API. Once you have a reference to a promise, you can call its then()
method to execute an action when the value becomes available, or when an error occurs.
Promises may also be created using the new Promise()
constructor. You don't need to import the Promise.jsm
module to use a Promise
object to which you already have a reference.
Internally, a promise can be in one of three states:
undefined
.undefined
, though it is generally an Error
object, like in exception handling.Note: You should always handle, forward, or report errors (rejection reasons). If you see the message "A promise chain failed to handle a rejection", there is likely something to be fixed in the code. See handling errors and common pitfalls below.
In documentation, the type of the fulfillment value is usually specified between angular brackets. For example, the OS.File.exists
function returns a promise that will eventually fulfill with a boolean:
Promise<boolean> exists(string path);
The rejection reason may be specified separately in the function's documentation, and is considered to be an Error
object unless otherwise specified.
Promise then([optional] Function onFulfill, [optional] Function onReject ); |
Promise catch([optional] Function onReject); |
Creates a new promise, initially in the pending state, and provides references to the resolving functions that can be used to change its state.
new Promise(executor);
executor
This function is invoked immediately with the resolving functions as its two arguments:
executor(resolve, reject);
The constructor will not return until the executor has completed. The resolving functions can be used at any time, before or after the executor has completed, to control the final state of the promise. If the executor throws an exception, its value will be passed to the reject
resolving function.
Fulfills the associated promise with the specified value, or propagates the state of an existing promise. If the associated promise has already been resolved, either to a value, a rejection, or another promise, this method does nothing.
aValue
argument, and then calling it again with another value before the promise is fulfilled or rejected, will have no effect the second time, as the associated promise is already resolved to the pending promise.void resolve( aValue );
aValue
Optionalundefined
, it becomes the fulfillment value of the associated promise. If this value is a promise, then the associated promise will be resolved to the passed promise, and follow the state as the provided promise (including any future transitions).Rejects the associated promise with the specified reason. If the promise has already been resolved, either to a value, a rejection, or another promise, this method does nothing.
void reject( aReason );
aReason
OptionalThe rejection reason for the associated promise. Although the reason can be undefined
, it is generally an Error
object, like in exception handling.
Calls one of the provided functions as soon as this promise is either fulfilled or rejected. A new promise is returned, whose state evolves depending on this promise and the provided callback functions.
The appropriate callback is always invoked after this method returns, even if this promise is already fulfilled or rejected. You can also call the then
method multiple times on the same promise, and the callbacks will be invoked in the same order as they were registered.
Warning: If the onFulfill
callback throws an exception, the onReject
callback is not invoked and the exception won't be caught, nor shown in the console (you will see a promise chain failed error). You can register a rejection callback on the returned promise instead (using catch() or then()), to process any exception occurred in either of the callbacks registered on this promise.
then
method multiple times on the same promise, the registered callbacks are always executed independently. For example, if an exception occurs in one callback, it does not affect the execution of subsequent callbacks. The behavior of the callback only affects the promise returned by the then
method with which the callback was registered, that is actually a different promise for each invocation of the method.Promise then( Function onFulfill, Function onReject );
onFulfill
Optionalthen
method. In case this parameter is not a function (usually null
), the new promise returned by the then
method is fulfilled with the same value as the original promise.onReject
OptionalIf the promise is rejected, this function is invoked with the rejection reason of the promise as its only argument, and the outcome of the function determines the state of the new promise returned by the then
method. In case this parameter is not a function (usually left undefined
), the new promise returned by the then
method is rejected with the same reason as the original promise.
A new promise that is initially pending, then assumes a state that depends on the outcome of the invoked callback function:
undefined
, the new promise is fulfilled with this fulfillment value, even if the original promise was rejected.Equivalent to then()
with an undefined
value for the onFulfill
parameter. If you chain then( onFulfill ).catch( onReject ), exceptions thrown in onFulfill will be caught and passed to onReject, which is not the case when just passing onReject to then().
Promise catch( Function onReject );
The following calls are therefore identical:
p.then(undefined, logError); p.catch(logError);
By design, the instant state and value of a promise cannot be inspected synchronously from code, without calling the then()
method.
To help with debugging, only when inspecting a promise object manually, you can see more information as special properties that are inaccessible from code (this, at present, is implemented by randomizing the property name, for the lack of more sophisticated language or debugger support).
These code-inaccessible, inspectable properties are:
{{private:status}}
: 0 for pending, 1 for fulfilled, or 2 for rejected.{{private:value}}
: Fulfillment value or rejection reason, for fulfilled or rejected promises only.{{private:handlers}}
: Array of objects holding references to functions registered by the then()
method, for pending promises only.See the examples page.
You should report unhandled errors, unless you're handing off the promise to a caller or another code path that will handle the error.
// ###### WRONG: Silently drops any rejection notified by "OS.File.Exists". OS.File.exists(path).then(exists => { if (exists) myRead(path); }); // ###### WRONG: Silently drops any exception raised by "myRead". OS.File.exists(path).then(exists => { if (exists) myRead(path); }, Components.utils.reportError); // CORRECT (for example, might report the exception "myRead is not defined") OS.File.exists(path).then(exists => { if (exists) myRead(path); }) .catch(Components.utils.reportError); // CORRECT (the function returns a promise, and the caller will handle the rejection) function myReadIfExists(path) { return OS.File.exists(path).then(exists => { if (exists) myRead(path); }); }