Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Today we’ll review the use of promise’s chained calls to solve sequential asynchronous operations.
Promise chain call
The most commonly used chained invocation in JS is the jQuery framework, as shown in the following code
$('.level1').click(function () {$(this)
.next()
.stop()
.slideToggle()
.parent()
.sibling()
.children('ul')
.slideUp();
});
Copy the code
The instance methods of the Promise object then(), catch(), and finally() actually return a Promise object.
Therefore, instance methods such as THEN () can be continuously called on the returned Promise object, which is called the promise chain.
Here’s a simple example
Create a Promise object that successfully returns the number 10 after 3 seconds.
let p = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(10);
}, 3 * 1000);
});
p.then((result) = > {
console.log(result);
return result * 2;
});
// Output after 3 seconds:
/ / 10
Copy the code
Inside the THEN () callback I return a new value result * 2, because THEN returns a new Promise object equal to the value of resolve. So you can continue calling the then method, as follows
let p = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(10);
}, 3 * 1000);
});
p.then((result) = > {
console.log(result);
return result * 2;
}).then((result) = > {
console.log(result);
return result * 3;
});
// Output after 3 seconds:
/ / 10
/ / 20
Copy the code
And it can go on and on
let p = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(10);
}, 3 * 1000);
});
p.then((result) = > {
console.log(result);
return result * 2;
}).then((result) = > {
console.log(result);
return result * 3;
}).then((result) = > {
console.log(result);
return result * 4;
});
// Output after 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code
More then
Instead of using chained calls, multiple then methods are called simultaneously on a promise
let p = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(10);
}, 3 * 1000);
});
p.then((result) = > {
console.log(result); / / 10
return result * 2;
})
p.then((result) = > {
console.log(result); / / 10
return result * 3;
})
p.then((result) = > {
console.log(result); / / 10
return result * 4;
});
// Output after 3 seconds:
/ / 10
/ / 10
/ / 10
Copy the code
In the example above, one Promise object, multiple THEN’s, none of which are related to each other. They are executed independently, not like the chain calls above.
In a real project, you would rarely call multiple THEN methods on a promise like this.
return new promise
We return a value in the then callback, which is equivalent to new a promise and reslove the value immediately.
So it looks like this
let p = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(10);
}, 3 * 1000);
});
p.then((result) = > {
console.log(result);
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(result * 2);
}, 3 * 1000);
});
}).then((result) = > {
console.log(result);
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(result * 3);
}, 3 * 1000);
});
}).then(result= > console.log(result));
// Output every 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code
Next, we can wrap a function that returns a promise
/ / promise
function generateNumber(num) {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(num);
}, 3 * 1000);
});
}
generateNumber(10)
.then(result= > {
console.log(result);
return generateNumber(result * 2);
})
.then((result) = > {
console.log(result);
return generateNumber(result * 3);
})
.then(result= > console.log(result));
// Output every 3 seconds:
/ / 10
/ / 20
/ / 60
Copy the code
As with the result above, we make a wrapper with the generateNumber function.
Promise chain syntax
In JS development, we often encounter the need to perform multiple asynchronous tasks in sequence. The next asynchronous task depends on the result of the previous asynchronous task. Without the promise, this would be the case with callback
Get('/user'.function(user) {
Get(`/level/${user.id}`.function(level) {
Get(`/info/${level.id}`.function(info) {
console.log(info)
})
})
})
Copy the code
Use the Promise chain call
getUser()
.then(result= > getLevel(result))
.then(result= > getInfo(result))
...
Copy the code
It looks a lot cleaner than the callback method, which is infinitely nested, with promises just continuing down then.
So let’s take a real example,
- Get data from the database
- Gets the items in the user’s shopping cart
- Calculate the total price of goods
Assume that all the above operations are asynchronous and need to be executed sequentially
function getUser(userId) {
return new Promise((resolve, reject) = > {
console.log('Get user information from database');
setTimeout(() = > {
resolve({
userId: userId,
username: 'admin'
});
}, 1000); })}function getServiceCart(user) {
return new Promise((resolve, reject) = > {
console.log(` access${user.username}Shopping cart goods');
setTimeout(() = > {
resolve([
{name: 'book'.price: 10},
{name: 'phone'.price: 200}]); },3 * 1000);
});
}
function getServiceCost(goods) {
return new Promise((resolve, reject) = > {
console.log(Calculate the total price of cart items:The ${JSON.stringify(goods)}. `);
setTimeout(() = > {
resolve(goods.reduce((total, cur) = > total + cur.price, 0));
}, 2 * 1000);
});
}
getUser(100)
.then(getServiceCart)
.then(getServiceCost)
.then(console.log);
/ / output:
// Get user information from the database
// Get admin's shopping cart items
/ / calculation purchases goods total: [{" name ":" book ", "price" : 10}, {" name ":" phone ", "price" : 200}].
/ / 210
Copy the code
Promise solved the problem of callback hell, but it wasn’t elegant enough.
The async/await keyword has been introduced in ES2017, which allows you to write more concise code than promise and write it later.
Today we learned about the use of the promise chain to handle multiple asynchronous tasks.
Welcome to pay attention to my public number [xiaoshuai’s programming notes], follow me a little bit of progress every day