
从JavaScript中的for...of说起(下)
在上一篇文章中,梳理了javascript中的两个重要概念:iterator和generator,并且介绍了两者在异步操作中的应用。
在异步操作中使用iterator和generator是一件比较费劲的事情,而ES2017给我们提供了更为简便的async和await。
async和await
async
mdn上说:async function 声明用于定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。
简单来说,如果你在一个函数前面使用了async关键字,那么这个函数就会返回一个promise。如果你返回的不是一个promise,JavaScript也会自动把这个值"包装"成Promise的resolve值。例如:
当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。例如下面的例子:
await
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。看下面的例子:
当代码执行到await语句时,会暂停执行,直到await后面的promise正常处理。这和我们之前讲到的generator一样,可以让代码在某个地方中断。只不过,在generator中,我们需要手动写代码去执行generator,而await则是像一个自带执行器的generator。某种程度上,我们可以理解为:await就是generator的语法糖。看下面的代码:
我们使用babel对这段代码进行转化,得到以下的代码:
通过变量名可以看到,babel也是将async await转换成了generator来进行处理的。
任务队列
以下的场景其实是很常见的:
我们有一堆任务,我们需要按照一定的顺序执行这一堆任务,拿到最终的结果。这里,把这一堆任务称为一个任务队列。
js中的队列其实就是一个数组。
同步任务队列
任务队列中的函数都是同步函数。这种情况比较简单,我们可以采用reduce很方便的遍历。
异步任务队列
任务队列中的函数都是异步函数。这里,我们假设所有的函数都是以Promise的形式封装的。现在,需要依次执行队列中的函数。假设异步任务队列如下:
koa2洋葱模型实现原理
koa2,大家都不陌生了。koa2的洋葱模型,是怎么实现的呢?先来看下面的代码:
其实实现起来很简单,app.use就是将所有的回调函数都塞进了一个任务队列里面,调用await next()的时候,会直接执行队列里面下一个任务,直到下一个任务执行完成,才会接着执行后续的代码。我们来简单实现一下最基本的逻辑:
写在后面
可以看到,使用async和await进行异步操作,可以使代码看起来更为清晰,简单。我们可以用同步代码的方式来书写异步代码。本文还探究了前端开发中很常见的任务队列的相关问题。通过本文和上一篇文章,我自己也对js中的异步操作有了更深入,更全面的认识。符合预期。
