async/await 是 ES2016 新加入的特性,它提供了用 for、if 等代码结构来编写异步的方 式。它的运行时基础是 Promise,面对这种比较新的特性,我们先来看一下基本用法。
async 函数必定返回 Promise,我们把所有返回 Promise 的函数都可以认为是异步函数。
async 函数对 Generator 函数的改进,体现在以下三点。
(1)内置执行器。 Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。
var result = asyncReadFile();
(2)更好的语义。 async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。 co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。
async 函数是一种特殊语法,特征是在 function 关键字之前加上 async 关键字,这样,就 定义了一个 async 函数,我们可以在其中使用 await 来等待一个 Promise。
function sleep(duration) { return new Promise(function(resolve, reject) { setTimeout(resolve,duration); }) } async function foo(){ console.log("a") await sleep(2000) console.log("b") }
这段代码利用了我们之前定义的 sleep 函数。在异步函数 foo 中,我们调用 sleep。 async 函数强大之处在于,它是可以嵌套的。我们在定义了一批原子操作的情况下,可以利 用 async 函数组合出新的 async 函数。
function sleep(duration) { return new Promise(function(resolve, reject) { setTimeout(resolve,duration); }) } async function foo(name){ await sleep(2000) console.log(name) } async function foo2(){ await foo("a"); await foo("b"); }
这里 foo2 用 await 调用了两次异步函数 foo,可以看到,如果我们把 sleep 这样的异步操 作放入某一个框架或者库中,使用者几乎不需要了解 Promise 的概念即可进行异步编程了。 此外,generator/iterator 也常常被跟异步一起来讲,我们必须说明 generator/iterator 并非异步代码,只是在缺少 async/await 的时候,一些框架(最著名的要数 co)使用这样的特性来模拟 async/await。 但是 generator 并非被设计成实现异步,所以有了 async/await 之后, generator/iterator 来模拟异步的方法应该被废弃。