The callback hell
That is, in asynchronous JS, when the execution of an asynchronous task depends on the result of another asynchronous task, it is common to nest the two asynchronous tasks. If there is too much nesting, the callback will nested the callback, making it difficult to intuitively understand the code.
(So it’s not a fancy word, so don’t let the name fool you.)
What is a Promise
Promise, a new syntax in ES6, is a solution to asynchronous programming that solves callback hell. It’s a constructor that has all, Reject, and resolve in it, and then, catch, and so on in its prototype.
(To put it bluntly, asynchronous code looks easy to understand.) Ex. :
let p = new Promise(function(resolve, reject){
// Do some asynchronous operations
setTimeout(function(){
console.log('Promise execution completed ');
resolve('Any data');
}, 2000);
});
Copy the code
An asynchronous operation, setTimeout, is performed, and after 2 seconds, “Execution complete” is printed and the resolve method is called.
Promise has three states
A Promise has three states. The initial state is pending.
Resolve can change to rejected, resolve can change to Resolved,
Once a state is changed, it cannot be changed again (the Promise specification states that states other than pending states cannot be changed).
Promise usage
In fact, an instance on a Promise. A Promise is an object, not a function. The argument function passed by a Promise executes immediately upon declaration, so the correct gesture for a Promise is to wrap another function around it and run the function if needed, as in:
<div onClick={promiseClick}> Start asynchronous request </div>const promiseClick =() = >{
console.log('Click method called')
let p = new Promise(function(resolve, reject){
// Do some asynchronous operations
setTimeout(function(){
console.log('Fulfill Promise');
resolve('The data to be returned can be any data such as the data returned by the interface');
}, 2000);
});
return p;
}
Copy the code
Executor (resolve, reject)
Executor is a function that takes resolve and reject.
The Executor function is called immediately upon execution of the Promise constructor, and resolve and reject are passed to the executor as arguments (the executor function is called before the Promise constructor returns the new object).
When the resolve and reject functions are called, the state of the promise will be fulfilled or Rejected, respectively. There are usually asynchronous operations performed internally by the executor. Once completed, you can call the resolve function to change the promise state to depressing, or the Reject function to change its state to Rejected if an error occurs.
.then
Each Promise instance object has a then method, which is used to process the results of the previous asynchronous logic.
The then method can take two callback functions as arguments. The first callback is called when the Promise object’s state becomes Resolved (when it succeeds) and takes the value in resove() parentheses in the Promise, which in this case is num; The second callback is called when the state of the Promise object changes to Rejected, with the value in reject() parenthesis, which in the following code is’ the number is too high for 10 to execute a failure callback ‘. The second function is optional and does not have to be provided. Both of these functions accept as arguments a value passed from the Promise object.
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('Random number generated value:',num)
if(num<=10){
resolve(num);
}
else{
reject('The number is too high for 10 to perform a failed callback'); }},2000);
})
return p
}
promiseClick().then(
function(data){
console.log('Resolved successful callback');
console.log('Successful callback accepted value:',data);
},
function(reason){
console.log('Rejected failed callback');
console.log('Failed to execute callback throw failure cause:',reason); });Copy the code
Execution Result:
Then chain calls
For a Promise’s then() method, then always returns a Promise instance, so you can always call then, in the form of run().then().then().then().then().then()…
When a then() method calls the state of asynchronous success, you can either return a definite “value” or return a Promise instance again.
When an exact value is returned, then will pass the exact value into a default generated Promise instance. This Promise instance will immediately be fulfilled as a pity state for use in the following THEN method. Look at the code:
let num = 0
let run = function() {
return new Promise(resolve= > {
resolve(`${num}`)})
}
run().then(val= > {
console.log(val)
return val
})
.then(val= >{
val++
console.log(val)
return val
})
.then(val= >{
val++
console.log(val)
})
// Output: 0, 1, 2
Copy the code
catch
A parallel method to the then method is catch, which is used to catch exceptions and is the same as the callback to the second parameter rejected in the then method (try catch), like this:
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('Random number generated value:',num)
if(num<=10){
resolve(num);
}
else{
reject('The number is too high for 10 to perform a failed callback'); }},2000);
})
return p
}
promiseClick().then(
function(data){
console.log('Resolved successful callback');
console.log('Successful callback accepted value:',data);
}
)
.catch(function(reason, data){
console.log('Catch rejected');
console.log('Catch failed to execute a callback throw because:',reason);
});
Copy the code
All usage
The all method, which is the equivalent of then, takes an array of Promise parameters. Then is called only after all promises in the array have successfully executed resolve, passing several Promise return values to then as arguments in an array. So results here is just an array of results. If a Promise fails and reject is called, the console reports an error with reject.
There is a scene that is very suitable for using all. Some applications with a lot of game materials can pre-load various resources such as pictures, Flash and various static files when opening the web page. After everything is loaded, we’ll initialize the page.
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('Random number generated value:',num)
if(num<=10){
resolve(num);
}
else{
reject('The number is too high for 10 to perform a failed callback'); }},2000);
})
return p
}
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('Random number generated value:',num)
if(num<=10){
resolve(num);
}
else{
reject('The number is too high for 10 to perform a failed callback'); }},2000);
})
return p
}
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('Random number generated value:',num)
if(num<=10){
resolve(num);
}
else{
reject('The number is too high for 10 to perform a failed callback'); }},2000);
})
return p
}
Promise.all([promiseClick3(), promiseClick2(), promiseClick1()])
.then(function(results){
console.log(results);
});
Copy the code
Execution Result:
Race usage
The effect of the all method is essentially “the slowest runner executes the callback,” as opposed to the “fastest runner executes the callback,” which is the race method, which is the word for race. Whoever completes first executes the callback first. Those that finish first will not enter any race callbacks, regardless of whether the callback succeeds or fails on race.
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('1s random number generated value: ',num)
if(num<=10){
resolve(num);
}
else{
reject('1S number is too high for 10 about to fail callback'); }},1000);
})
return p
}
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('2s random number generated value: ',num)
if(num<=10){
resolve(num);
}
else{
reject('2S number is too high for 10 about to fail callback'); }},2000);
})
return p
}
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); // Generate random numbers from 1 to 10
console.log('3s random number generated value: ',num)
if(num<=10){
resolve(num);
}
else{
reject('3S number too 10 about to fail callback'); }},3000);
})
return p
}
Promise
.race([promiseClick3(), promiseClick2(), promiseClick1()])
.then(function(results){
console.log('success',results);
},function(reason){
console.log('failure',reason);
});
Copy the code
Execution Result:
Examples of real-world code
// Execute the search help interface to get data
const getShTableData = val= > {
const { table, initialValue = {} } = searchHelper;
return new Promise(async (resolve, reject) => {
if (process.env.MOCK_DATA === 'true') {
await sleep(500);
const { data } = cloneDeep(require('@/mock/tableData').default);
return resolve(data.items);
} else {
constparams = merge({}, table.fetch? .params, formatParams({ ... initialValue, ... createShFilters(val) }), {currentPage: 1.pageSize: 500 });
try {
const res = await table.fetch.api(params);
if (res.code === 200) {
const list = get(res.data, table.fetch.dataKey) ?? (Array.isArray(res.data) ? res.data : []);
returnresolve(list); }}catch(err) {} reject(); }}); }; getShTableData(val) .then(list= > resetSearchHelperValue(list, val))
.catch(() = > clearSearchHelperValue(!0));
Copy the code
Write a Promise
When interviewers think you might be a big shot, they’ll often ask you to write a Promise that proves you’re worth a big salary.
var a=1;
const PENDING='pending';
const RESOLVED='resolved';
const REJECTED='rejected';
function myPromise(fn){
const that=this;
that.state=PENDING;
that.resolvedCallbackArray=[];
that.rejectedCallbackArray=[];
function resolve(value){
that.state=RESOLVED;
that.resolvedCallbackArray.forEach(cbFn= >cbFn(value));
}
function reject(value){
that.state=REJECTED;
that.rejectedCallbackArray.forEach(cbFn= >cbFn(value))
console.log('reject calls',value)
}
try{
fn(resolve,reject);
}catch(e){
reject(e);
}
}
myPromise.prototype.then=function(onFulfilled,onRejected){
const that=this;
that.resolvedCallbackArray.push(onFulfilled);
that.rejectedCallbackArray.push(onRejected);
returnthat; }function f(){
return new myPromise((resolve,reject) = >{
if(a===1) {setTimeout(() = >{
resolve('success');
},2000)}else{
reject('failure')
}
})
}
f().then(value= >{
console.log('First time',value)
})
Copy the code
Execution Result: