明天遇到一个数组排序的坑,是对于ES6的异步语法糖async/await。简略地记录下:
遇坑
起因是须要在forEach的匿名函数里await一个异步函数,于是直观地在匿名函数前加async,简略例子如下,
// 跳序codefunction makePromise(num) { return new Promise(resolve => { resolve(num) });}[1,2,3,4,5,6].forEach(async (num) => { if (num % 2 == 0) { let pmnum = await makePromise(num); console.log(pmnum) } else { console.log(num) }});
大家认为打印程序是什么?这里比拟容易误导开发,因为应用await就是为了让代码看起来像同步执行,所以输入应该会是程序1到6。
然而答案是——1,3,5,2,4,6
后果await前面的代码块被阻塞了。
发问
如果咱们晋升async的作用域,使其蕴含遍历,
// 程序codeasync function exc() { for (let num of [1,2,3,4,5,6]) { if (num % 2 == 0) { let pmnum = await makePromise(num); console.log(pmnum) } else { console.log(num) } }}exc();
1,2,3,4,5,6
这次await并没有阻塞,代码像是同步执行,两者有什么区别呢?是什么导致输入的程序不一样?
解答
先实现本人的forEach函数,
Array.prototype.myForEach = function(callback) { for (var i = 0; i < this.length; i++) callback(this[i], i, this);};
代替原生的forEach,后果也是跳序1,3,5,2,4,6
。
咱们能够看出跳序和程序code区别在于遍历里的callback是否异步,即前者是在遍历中执行异步办法,后者是在异步办法里执行遍历。跳序code等价于上面的代码段:
// 跳序code2async function exc2(num) { if (num % 2 == 0) { let pmnum = await makePromise(num); console.log(pmnum) } else { console.log(num) }}for (let num of [1,2,3,4,5,6]) { exc2(num);}
JavaScript引擎都是单线程执行的,实际上执行到async办法时,无论其办法外部有没有阻塞,引擎都会持续往下跑,所以跳过了246。
理解ES6 await的机制之后,咱们晓得当运行到await时,会阻塞其前面的代码,但仅限于其所在的async办法外部,简略来说,此时整个async办法都在期待await的返回,运行环境盏又切换到async办法内部,继续执行。
综上所述,跳序code2的运行状况如下
run exc2(1) ↓run exc2(2) → 遇到await,期待 ↓run exc2(3) ↓ run exc2(4) → 遇到await,期待 ↓run exc2(5) ↓ run exc2(6) → 遇到await,期待 ↓over异步返回2 → run exc2(2)余下的代码 → over异步返回4 → run exc2(4)余下的代码 → over异步返回6 → run exc2(6)余下的代码 → over
所以,输入是1,3,5,2,4,6
课后作业
如果exc2不是async办法,输入的应该是1,2,3,4,5,6
大家能够像下面那样推算一下程序code的运算程序。