async await 和Promise的结合使用,Promise链解决循环异步请求,循环依次执行异步代码
需求分析当我们想依次执行多个异步请求时,或者实现setTimeout为setInterval时,可以使用Promise对象和async await关键字来实现该功能。尤其是,我们在使用node做网络爬虫时,需要进行大量的依次进行的异步请求。波及到的知识点如下:1、数组的reduce方法reduce()方法对数组中的每个元素执行一次处理函数,将其结果汇总为单个返回值。reduce详情:https:/
需求分析
当我们想依次执行多个异步请求时,或者实现setTimeout为setInterval时,可以使用Promise对象和async await关键字来实现该功能。
尤其是,我们在使用node做网络爬虫时,需要进行大量的依次进行的异步请求。
波及到的知识点如下:
1、数组的reduce方法
reduce()
方法对数组中的每个元素执行一次处理函数,将其结果汇总为单个返回值。
reduce详情:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
2、Promise
微任务,立即执行的函数,resolve和reject为完成状态下执行的方法。
3、async和await
async函数执行结果为一个Promise对象;await 等待一个Promise执行完成后的结果,即resolve或reject的值。
实现代码:
注意:reduce方法中,有两种实现方式。
reduce必须接收一个Promise对象,且每次执行reduce处理函数,都是一个Promise对象,所以reduce的处理函数返回值必须为Promise
setTime函数是一个异步方法,所以必须要用async await来等待setTime异步函数的执行完成。
因此我们的写法如下:
var setTime = function(v){
return new Promise(function(resolve, reject){
setTimeout(()=> {
console.log(v)
resolve();
}, 1000)
})
}
var arr = [10,20,30,40];
arr.reduce(async function(acc,cur,index){
return acc.then(() => {
//第二种实现方法
// return new Promise(async (resolve, reject) => {
// await setTime(cur);
// resolve();
// })
return (async function a(){
//await之前的宏任务,因为上一个异步的await完成后,就会立即执行该宏任务
//console.log(cur)
await setTime(cur);
//await之后的宏任务,该await执行完后,立即执行后面的宏任务,相当于对该await的补充
// console.log(cur)
})()
})
},Promise.resolve())
深入理解:
核心思想是:宏任务执行建一个Promise链,类似下面这种:——Promise链是宏任务瞬间执行完成的,结合数组reduce累加器可以累加构造Promise链
Promise.resolve().then(异步处理函数1).then(异步处理函数2).then....
所以我们的代码目的是建Promise链,比如下面这种写法:
var setTime = function (v) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log(v)
resolve();
}, 1000)
})
}
var arr = [10, 20, 30, 40];
arr.reduce(async function (acc, cur, index) {
return acc.then(() => {
return setTime(cur);
})
}, Promise.resolve())
我们的目的是构造Promise链,如下也是可以的:
var setTime = function (v) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log(v)
resolve();
}, 1000)
})
}
var p = Promise.resolve();
for(let i = 0; i < 5; i++){
p = p.then(function(){
return setTime(i);
})
}
你是怎么想的呢?
封装一个Promise链函数
注意:for循环内的宏任务瞬间执行完,执行次数为arr.length - 1,之后是promise链的链式执行;
let promiseChain = function (arr) {
let setTime = (v => {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log(v)
resolve();
}, 1000)
})
})
let p = Promise.resolve();
for (let i = 0; i < arr.length; i++) {
console.log(1111) // 注意此处瞬间执行完,执行了arr.length -1 次
p = p.then(function () {
return setTime(arr[i]);
})
}
}
let arr = ['a','b','c']
promiseChain(arr);
如下修改请注意:
如果不使用let 或 const 而是使用的var,那么promise链执行结果为arr[length-1]的值,所以此处的let和const 块作用域也相当关键
for (var i = 0; i < arr.length; i++) {
var m = arr[i]
p = p.then(function () {
return setTime(m);
})
}
如果使用async和await,整个for循环在执行到await时都会等待
async function message() {
for (let item of arr) {
console.log(item)
await new Promise(function (resolve, reject) {
setTimeout(() => {
console.log(item)
resolve();
}, 1000)
})
}
}
message()
打印结果:
立即打印a——1s后,打印a b——1s后打印b c——1s后打印c
更多推荐
所有评论(0)