Asynchronous solution — Promise
preface
Asynchronous programming module is becoming more and more important in front-end development. From the very beginning of XHR to the encapsulation of Ajax, attempts have been made to solve the problem of asynchronous programming. With the advent of the new ES6 standard, there are new solutions for handling asynchronous data flows. In traditional Ajax requests, when data between asynchronous requests was dependent on each other, inelegant layers of callbacks, commonly known as “callback hell,” could be a bit daunting. Promise was the way to move away from callback hell and write more elegant asynchronous code.
The downside of callback hell is the following:
- Code bloat.
- Poor readability.
- The coupling degree is too high and the maintainability is poor.
- Poor code reuse.
- Bug prone.
- Exceptions can only be handled in callbacks.
In practice, it turns out that promises aren’t perfect. Async/Await is one of the most revolutionary features added to JavaScript in recent years. Async/Await provides an alternative way to make asynchronous code look like synchronous code. Let’s take a look at these two options for handling asynchronous programming.
What is a Promise
Promise is a solution to asynchronous programming:
Syntactically, a Promise is an object that fetches messages for asynchronous operations;
In its original sense, it is a promise that will give you results over time.
This is a big pity. There are three states of promise: pending, successful, and rejected.
Once the state has changed, it will never change.
Once a Promise instance is created, it executes immediately.
Look at some familiar code:
// Promise is a constructor that has all, Reject,resolve,race methods on its own and then, catch, and so on on its prototype
let p = new Promise((resolve,reject) = >{
// Do some asynchronous operations
setTimeout((a)= >{
/* let res = {ok:1, data:{name:" "}} */
let res = {
ok:0.error:new Error('wrong')}if(res.ok === 1){
resolve(res.data);
}else{
reject(res.error.message)
}
}, 1000)})Copy the code
The state and value of the Promise
Promise objects can be in three states
- Pending
- This is a big pity.
- Rejected(failed)
The state can only change from Pending to depressing or from Pending to Rejected. After the state changes, it will not change again and will always remain in this state.
The Promise value is the value passed to the callback function when the state changes
The arguments in the above example, resolve and reject, are functions that change the state of a Promise and the value of the incoming Promise
Resolve and reject
resolve
: Changes the state of the Promise object fromPending
intoThis is a big pity.
reject
: Changes the state of the Promise object fromPending
intoRejected(failed)
resolve
和reject
Can be passed a value of any type as an argumentPromise
Object successfully(Fulfilled)
And failure(Rejected)
The value of the
Then method
p.then((data) = >{
console.log(data);
return data;
},(error)=>{
console.log(error)
}).then(data= >{
console.log(data);
})
Copy the code
The promise’s then method returns a Promise object, so the chain call can continue
We can continue to modify the above code, because the above code does not pass parameters
function timeout(ms) {
return new Promise((resolve, reject) = > {
setTimeout((a)= > {
resolve('hello world')
}, ms);
})
}
timeout(1000).then((value) = > {
console.log(value);
})
Copy the code
Rules for the THEN method
then
The next input to the method requires the last output- If another promise is returned after a promise is executed, the execution result of the promise is passed to the next time
then
In the - if
then
Returns a normal value instead of a Promise object, which will be the result of the success of the next THEN - If the current
then
If you fail, you go nextthen
The failure of the - If undefined is returned, success or failure will be followed by the next success
- Catch is when an error is not handled
then
If the method is not written to, the value is passed through to the next onethen
In the
Promise encapsulates XHR objects
const getJSON = function (url) {
return new Promise((resolve, reject) = > {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept'.'application/json');
xhr.send();
function handler() {
console.log(this.readyState);
if (this.readyState ! = =4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
}
})
}
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
.then((res) = > {
console.log(res);
}, function (error) {
console.error(error);
})
// Chain calls to the then method
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
.then((res) = >{
return res.HeWeather6;
}).then((HeWeather6) = >{
console.log(HeWeather6);
})
Copy the code
Catch method
Catch (err=>{}) is equivalent to then(null,err=>{})
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
.then((json) = > {
console.log(json);
}).then(null,err=>{
console.log(err);
})
/ / equivalent to the
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
.then((json) = > {
console.log(json);
}).catch(err= >{
console.log(err);
})
Copy the code
resove()
The resolve() method will convert the existing object into a Promise object, and the state of this instance is fulfilled
let p = Promise.resolve('foo');
New Promise(resolve=>resolve('foo'));
p.then((val) = >{
console.log(val);
})
Copy the code
reject()
The Reject () method returns a new Promise instance with the status Rejected
let p2 = Promise.reject(new Error('Wrong'));
// let p2 = new Promise((resolve,reject)=>reject(new Error(' Error ')));
p2.catch(err= > {
console.log(err);
})
Copy the code
All () method
The all() method provides the ability to execute asynchronous operations in parallel and not execute callbacks until all asynchronous operations are complete
Imagine a page chat system where we need to obtain the user’s personal information and friend list from two different urls. These two tasks can be performed in parallel, using promise.all as shown below
let meInfoPro = new Promise( (resolve, reject) = > {
setTimeout(resolve, 500.'P1');
});
let youInfoPro = new Promise( (resolve, reject) = > {
setTimeout(resolve, 600.'P2');
});
// execute p1 and p2 at the same time, and execute then after they are both complete:
Promise.all([meInfoPro, youInfoPro]).then( (results) = > {
console.log(results); // Get an Array: ['P1', 'P2']
});
Copy the code
Race () method
Sometimes, multiple asynchronous tasks are fault tolerant. For example, reading a user’s personal information from two urls at the same time only needs to get the result returned first. In this case, use promise.race () to implement:
let meInfoPro1 = new Promise( (resolve, reject) = > {
setTimeout(resolve, 500.'P1');
});
let meInfoPro2 = new Promise( (resolve, reject) = > {
setTimeout(resolve, 600.'P2');
});
Promise.race([meInfoPro1, meInfoPro2]).then((result) = > {
console.log(result); // P1
});
Copy the code
Promise.all accepts an array of Promise objects, and after all completion, success will be executed uniformly;
Promise.race accepts an array of Promise objects, and as long as one completes, success is executed
For a more concrete example, deepen your understanding of the race() method
When we request an image resource, it will take too long to give feedback to the user
Use RACE to set a timeout for an asynchronous request and perform the corresponding operation after the timeout
function requestImg(imgSrc) {
return new Promise((resolve, reject) = > {
var img = new Image();
img.onload = function () {
resolve(img);
}
img.src = imgSrc;
});
}
// The delay function is used to time the request
function timeout() {
return new Promise((resolve, reject) = > {
setTimeout((a)= > {
reject('Image request timed out');
}, 5000);
});
}
Promise.race([requestImg('images/2.png'), timeout()]).then((data) = > {
console.log(data);
}).catch((err) = > {
console.log(err);
});
Copy the code
In addition to the above Api use of Promise, in fact, we need to understand more is the Promise of A+ specification is how to achieve, which is often asked in the interview, I hope the old iron come on