我们写代码的时候,通常希望代码能按照我们写的顺序来执行;例如:
async function test() {
let arr = [3, 2, 1]
arr.forEach(async item => {
const res = await handle(item)
console.log(res)
})
console.log('结束')
}
function handle(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 1000 * x)
})
}
test()
我们更希望上边的实行结果为
3
2
1
结束
但是,真实情况是
结束
1
2
3
why
想知道问题的原因,就的知道forEach底层代码到底是怎么样的
const myForEach = function(fn) {
let i
for(i=0; i<this.length; i++){
fn(this[i], i)
}
}
可以看到,forEach 拿过来直接执行了,这就导致它无法保证异步任务的执行顺序。
solution
解决方法: for of
async function test() {
let arr = [3, 2, 1]
for(const item of arr) {
const res = await handle(item)
console.log(res)
}
console.log('结束')
}
function handle(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 1000 * x)
})
}
test()
结果:
3
2
1
结束
what is the fuck about ( for of)?
其实for...of并不像forEach那么简单粗暴的方式去遍历执行,而是采用一种特别的手段——迭代器 去遍历。 首先,对于数组来讲,它是一种可迭代数据类型。那什么是可迭代数据类型呢?
可迭代数据类型:原生具有[Symbol.iterator]属性数据类型为可迭代数据类型。如数组、类数组(如arguments、NodeList)、Set和Map。
let arr = [3, 2, 1];
// 这就是迭代器
let iterator = arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// {value: 3, done: false}
// {value: 2, done: false}
// {value: 1, done: false}
// {value: undefined, done: true}
好,现在我们把iterator用一到我们最开始的代码中;如下
function handle(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 1000 * x)
})
}
async function test() {
let arr = [3, 2, 1]
let iterator = arr[Symbol.iterator]();
let res = iterator.next();
while(!res.done) {
let value = res.value;
console.log(value);
await handle(value);
res = iterator.next();
}
console.log('结束')
}
test()
打印一下结果:
// 3
// 2
// 1
// 结束
结论: 多个任务成功地按照顺序执行;那么回到for...of ,for...of其实是这段代码的语法糖。