A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation, resulting in a value.
The Promise constructor is primarily used to wrap functions that do not already support promises.
Essentially, a promise is a returned object to which you attach callbacks instead of passing callbacks into a function.
A callback can be added to a promise with the use of the then()
method. Multiple callbacks can be added by calling then()
several times. Each callback is executed one after another, in the order they were inserted.
Syntax
new Promise(executor)
Parameters
executor
A function that is passed with the argumentsresolve
andreject
.
The executor is called to initiate asynchronous work before thePromise
constructor even returns the created object.
Once the executor finishes it's work, calls theresolve
function to resolve the promise or else rejects it if an error occurred.
If an error is thrown in the executor function, the promise is rejected.
The return value of the executor is ignored.
Description
A Promise
is a proxy for a value not necessarily known when the promise is created.
It allows you to associated handlers with async action's eventual success value or failure reason.
This lets async methods return values like synchronous methods: instead of immediately returning the final value, the async method returns a promise to supply the value at some point in the future.
A Promise
is in one of these states:
pending: initial state, neither fulfilled nor rejected.
fulfilled: operation completed successfully.
rejected: operation failed.
A Promise
can be either fulfilled with a value or rejected with a reason (error).
When either case happens, the associated handlers queued up by a promises's then
method are called.
As the Promise.prototype.then()
and Promise.prototype.catch()
methods return promises, and can be chained.
Basic Structure
const myPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
// resolve(someValue); // fulfilled
// or
// reject("failure reason"); // rejected
})
Old "Callback Style" vs. Promises
Imagine a function, createAudioFileAsync()
, which asynchronously generates a sound file given a configuration record and two callback functions, one called if the audio file is successfully created, and the other called if an error occurs.
Here's some code that uses createAudioFileAsync()
:
function successCallback(result) {
console.log('Audio file ready at URL: ' + result)
}
function failureCallback(error) {
console.error('Error generating audio file: ' + error)
}
createAudioFileAsync(audioSettings, successCallback, failureCallback)
…modern functions return a promise you can attach your callbacks to instead:
If createAudioFileAsync()
were rewritten to return a promise, using it could be as simple as this:
createAudioFileAsync(audioSettings).then(successCallback, failureCallback)
That's shorthand for:
const promise = createAudioFileAsync(audioSettings)
promise.then(successCallback, failureCallback)
Chaining
A common need is to execute two or more asynchronous operations back to back, where each subsequent operation starts when the previous operation succeeds, with the result from the previous step. We accomplish this by creating a promise chain.
Here's the magic: the then()
function returns a new promise, different from the original:
const promise = doSomething()
const promise2 = promise.then(successCallback, failureCallback)
or
const promise2 = doSomething().then(successCallback, failureCallback)
This second promise (promise2
) represents the completion not just of doSomething()
, but also of the successCallback
or failureCallback
you passed in, which can be other asynchronous functions returning a promise. When that's the case, any callbacks added to promise2
get queued behind the promise returned by either successCallback
or failureCallback
.
Basically, each promise represents the completion of another asynchronous step in the chain.
Promise Prototype Methods
Promise.prototype.catch()
Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, OR to its original fulfillment value if the promise is instead fulfilled.
Promise.prototype.then()
Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler, or to its original settled value if the promise was not handled (i.e. if the relevant handler
onFulfilled)
oronRejected
is not a function).
Promise.prototype.finally()
Appends a handler to the promise, and returns a new promise which is resolved when the original promise is resolved. The handler is called when the promise is settled, whether fulfilled or rejected.
Examples
To provide a function with promise functionality, simply have it return a promise:
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.onload = () => resolve(xhr.responseText)
xhr.onerror = () => reject(xhr.statusText)
xhr.send()
})
}
Using Promise
and XMLHttpRequest
to load an image:
function imgLoad(url) {
// Create new promise with the Promise() constructor;
// This has as its argument a function
// with two parameters, resolve and reject
return new Promise(function (resolve, reject) {
// Standard XHR to load an image
var request = new XMLHttpRequest()
request.open('GET', url)
request.responseType = 'blob'
// When the request loads, check whether it was successful
request.onload = function () {
if (request.status === 200) {
// If successful, resolve the promise by passing back the request response
resolve(request.response)
} else {
// If it fails, reject the promise with a error message
reject(Error("Image didn't load successfully; error code:" + request.statusText))
}
}
request.onerror = function () {
// Also deal with the case when the entire request fails to begin with
// This is probably a network error, so reject the promise with an appropriate message
reject(Error('There was a network error.'))
}
// Send the request
request.send()
})
}
// Get a reference to the body element, and create a new image object
var body = document.querySelector('body')
var myImage = new Image()
// Call the function with the URL we want to load, but then chain the
// promise then() method on to the end of it. This contains two callbacks
imgLoad('myLittleVader.jpg').then(
function (response) {
// The first runs when the promise resolves, with the request.response
// specified within the resolve() method.
var imageURL = window.URL.createObjectURL(response)
myImage.src = imageURL
body.appendChild(myImage)
// The second runs when the promise
// is rejected, and logs the Error specified with the reject() method.
},
function (Error) {
console.log(Error)
}
)
Top comments (0)