async 并发执行和继发执行

面试题继发执行 : 1s后执行10,等1s后输出20,再等1s后输出30

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/javascript">
function Pro(val) {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve(val)
}, 1000)
})
}

async function log(arrs) {
for(const item of arrs) {
var response = await Pro(item);
console.log(response);
}
}

log([10, 20, 30])
</script>


问题:给定一个 URL 数组,如何实现接口的继发和并发?

async 继发实现:

继发一

1
2
3
4
5
6
async function loadData() {
var res1 = await fetch(url1);
var res2 = await fetch(url2);
var res3 = await fetch(url3);
return"whew all done";
}

继发二

1
2
3
4
5
6
async function loadData(urls) {
for (const url of urls) {
const response = await fetch(url);
console.log(await response.text());
}
}

async 并发实现:

并发一

1
2
3
4
async function loadData() {
var res = awaitPromise.all([fetch(url1), fetch(url2), fetch(url3)]);
return"whew all done";
}

并发二

1
2
3
4
5
6
7
8
9
10
11
12
async function loadData(urls) {
// 并发读取 url
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});

// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}

并发三[for await of]

for of方法能够遍历具有Symbol.iterator接口的同步迭代器数据,但是不能遍历异步迭代器。
ES9新增的for await of可以用来遍历具有Symbol.asyncIterator方法的数据结构,也就是异步迭代器,且会等待前一个成员的状态改变后才会遍历到下一个成员,相当于async函数内部的await。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// for of遍历
function Gen (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time)
}, time)
})
}
async function test () {
let arr = [Gen(2000), Gen(100), Gen(3000)] // 并发执行
for (let item of arr) {
console.log(Date.now(), item.then(console.log))
}
}
test()



// 1576391094972 Promise {<pending>}
// 1576391094973 Promise {<pending>}
// 1576391094973 Promise {<pending>}
// Promise {<resolved>: undefined}
// 100
// 2000
// 3000

上述代码证实了for of方法不能遍历异步迭代器,得到的结果并不是我们所期待的,于是for await of就粉墨登场啦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Gen (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(time)
}, time)
})
}
async function test () {
let arr = [Gen(2000), Gen(100), Gen(3000)] // 并发执行
for await (let item of arr) {
console.log(Date.now(), item) // 按次序输出
}
}
test()
// 1575536194608 2000
// 1575536194608 100
// 1575536195608 3000
使用for await of遍历时,会等待前一个Promise对象的状态改变后,再遍历到下一个成员。

for await of 和 并发二 的有异曲同工之妙!!!

1
2
3
4
5
6
7
8
9
10

// 按次序输出
for await (let item of arr) {
console.log(Date.now(), item) // 按次序输出
}

// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise); // 按次序输出
}