Promise introduction
Promise asynchronous programming solution is more reasonable and powerful than the traditional solution (callback function), mainly to solve the problem of callback hell.
What is hell? Look at the following code:
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Get the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback);
Is it hard to read the above code? The above forms a classic callback hell.
Now rewrite the above code through Promise:
doSomething().then(function(result) { return doSomethingElse(result); }) .then(function(newResult) { return doThirdThing(newResult); }) .then(function(finalResult) { console.log('Get the final result: ' + finalResult); }) .catch(failureCallback);
characteristic
-
The state of the object is not affected by the outside world.
Promise object represents an asynchronous operation and has three states:pending: in progress.
Fully: completed successfully
rejected: failedOnly the result of asynchronous operation can determine the current state, and no other operation can change this state.
-
Once the state changes, it will not change again. This result can be obtained at any time.
There are only two possibilities for the state of the Promise object to change: from Pending to Resolved and from Pending to Rejected. As long as these two situations occur, the state will solidify, will not change again, and will always maintain this result. Even if the change has occurred, you will get this result immediately if you add a callback function to the Promise object. This is completely different from events. The characteristic of events is that if you miss it and listen again, you won't get results.
advantage
- Chain operation reduces coding difficulty
- Code readability is significantly enhanced
shortcoming
- Promise cannot be cancelled. Once it is created, it will be executed immediately. It cannot be cancelled halfway.
- If the callback function is not set, the error thrown by Promise will not be reflected to the outside.
- When it is in Pending status, it is impossible to know which stage it has reached (just started or about to be completed).
Example method
(1) then is the callback function when the instance state changes. The first parameter is the callback function in the resolved state, and the second parameter is the callback function in the rejected state
(2) The then method returns a new promise instance, which is why promise can be chained
getJSON("/posts.json").then(function(json) { return json.post; }).then(function(post) { // ... });
(3)catch
The catch() method is then(null, rejection) or An alias for then(undefined, rejection), which specifies the callback function when an error occurs
getJSON('/posts.json').then(function(posts) { // ... }).catch(function(error) { // Error occurred when processing getJSON and the previous callback function console.log('An error occurred!', error); });
(4)finally()
The finally() method is used to specify the operation that will be performed regardless of the final state of the Promise object
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
Constructor method
(1)all
Promise. The all () method is used to wrap multiple promise instances into a new promise instance
const p = Promise.all([p1, p2, p3]);
Accept an array (iteration object) as a parameter. All array members should be Promise instances
The status of instance p is determined by p1, p2 and p3, which are divided into two types:
- Only when the states of p1, p2 and p3 become fully, the state of p will become fully. At this time, the return values of p1, p2 and p3 form an array and are passed to the callback function of p
- As long as one of p1, p2 and p3 is rejected, the status of p will become rejected. At this time, the return value of the first rejected instance will be passed to the callback function of p
Note that if the Promise instance as a parameter defines its own catch method, once it is rejected, it will not trigger Promise Catch method of all()
(2)race()
Promise. The race () method also wraps multiple promise instances into a new promise instance
const p = Promise.race([p1, p2, p3]);
As long as one of p1, p2 and p3 takes the lead in changing the state, the state of p will change accordingly
The return value of the Promise instance changed first is passed to the callback function of p
(3)allSettled()
Promise. The allsettled () method takes a set of promise instances as parameters and wraps them into a new promise instance
The wrapper instance will not end until all of these parameter instances return results, whether fully or rejected
const promises = [ fetch('/api-1'), fetch('/api-2'), fetch('/api-3'), ]; await Promise.allSettled(promises); removeLoadingIndicator();
(4)resolve()
Convert existing objects to Promise objects
Promise.resolve('foo') // Equivalent to new Promise(resolve => resolve('foo'))
Parameters can be divided into four cases as follows:
- The parameter is a Promise instance, Promise Resolve will return the instance intact without any modification
- The parameter is a thenable object, Promise Resolve turns the object into a Promise object, and then immediately executes the then() method of the thenable object
- The parameter is not an object with a then() method, or it is not an object at all, Promise Resolve () returns a new Promise object with the status resolved
- When there are no parameters, a Promise object in resolved state is returned directly
(5)reject()
Promise. The reject (reason) method will also return a new promise instance with the status of rejected
const p = Promise.reject('Error '); // Equivalent to const p = new Promise((resolve, reject) => reject('Error ')) p.then(null, function (s) { console.log(s) }); // Error
Usage scenario
Write the picture loading as a Promise. Once the loading is completed, the Promise state will change
const preloadImage = function (path) { return new Promise(function (resolve, reject) { const image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; }); };
Through chain operation, multiple rendering data are given to then to perform their respective duties. Or when the next asynchronous request depends on the result of the previous request, we can also solve the problem friendly through chain operation
// attend to each one 's own duties getInfo().then(res=>{ let { bannerList } = res //Rendering a carousel console.log(bannerList) return res }).then(res=>{ let { storeList } = res //Render store list console.log(storeList) return res }).then(res=>{ let { categoryList } = res console.log(categoryList) //Render classification list return res })
Multiple requests are merged through all() to summarize all the request results. You only need to set one loading
function initLoad(){ // loading.show() / / loading Promise.all([getBannerList(),getStoreList(),getCategoryList()]).then(res=>{ console.log(res) loading.hide() //Close loading }).catch(err=>{ console.log(err) loading.hide()//Close loading }) } //Data initialization initLoad()
Through race, you can set the timeout of picture request
//Request a picture resource function requestImg(){ var p = new Promise(function(resolve, reject){ var img = new Image(); img.onload = function(){ resolve(img); } //img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg "; correct img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg1"; }); return p; } //A delay function used to time requests function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject('Picture request timeout'); }, 5000); }); return p; } Promise .race([requestImg(), timeout()]) .then(function(results){ console.log(results); }) .catch(function(reason){ console.log(reason); });