async/await

基础概念

JavaScript 是单线程的,为了处理异步操作,先是使用回调函数,接着使用 Promise,然后又使用 generator/yield,最后到本文要介绍的 async/await。

引用阮一峰大大的一句话 async 函数就是 generator 函数的语法糖。

首先看一个结合 Promise 和 generator 处理异步的例子:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var fs = require('fs')

var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) {
reject(error)
}
resolve(data)
})
})
}

function run (taskDef) {
let task = taskDef()
let result = task.next()

function step () {
if (!result.done) {
let promise = Promise.resolve(result.value)
promise.then(function (value) {
result = task.next(value)
step()
}).catch(function (err) {
result = task.throw(err)
step()
})
}
}

step()
}

var generator = function * (){
var f1 = yield readFile('./verify.js')
var f2 = yield readFile('./readline.js')
console.log(f1.toString())
console.log(f2.toString())
}

run(generator)

通过这个例子,大家也看出来了,用 generator 函数处理异步的麻烦之处在于,它还需要自己定义执行器。

接下来用 async 函数改写这个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var fs = require('fs')

var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) {
reject(error)
}
resolve(data)
})
})
}

var asyncInstance = async function () {
var f1 = await readFile('./verify.js')
var f2 = await readFile('./readline.js')
console.log(f1.toString())
console.log(f2.toString())
}

asyncInstance()

一比较就会发现,async 函数就是将 generator 函数的星号(*)替换成 async,将 yield 替换成 await。而且 async 函数不需要自己定义执行器!

注意事项

  1. 区别于生成器的定义,可以使用箭头函数定义 async。
  2. 与 yield 一样,await 只能用在 async 函数内部,用于其他任意位置都是语法错误,即使在 async 函数内部的函数中也不行。
  3. async 函数返回的是 Promise 实例。
  4. 如果 async 函数内抛出了错误,并且没有被 try...catch 包裹,async 会直接以该错误作为原因,返回一个状态为 rejected 的 Promise 实例。
  5. 如果 await 后面是一个非 Promise 非 thenable 的值,则直接返回。
  6. 如果 await 后面是一个 Promise 实例。
    6.1 当 Promise 实例被 fulfill 时,返回 Promise 实例的值。
    6.2 当 Promise 实例被 reject 时,则将 Promise 被 reject 的值作为错误在此处抛出(同 4)。
  7. 如果 await 后面是一个 thenable 对象,会现将其作为 Promise 实例进行处理(同 6)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const asyncFun = async () => {
return 'resolved'
}

const promise = asyncFun();
promise
.then(
(value) => {
// resolved
console.log(value)
}
)
.catch(err => {
console.log(err)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const asyncFun = async () => {
throw 'err'
}

const promise = asyncFun();
promise
.then(
(value) => {
console.log(value)
}
)
.catch(err => {
// err
console.log(err)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const asyncFun = async () => {
await Promise.reject('rejected')
}

const promise = asyncFun();
promise
.then(
(value) => {
console.log(value)
}
)
.catch(err => {
// rejected
console.log(err)
})


感谢您的阅读,如果发现文章中有错误或漏洞,请批评指正。
邮箱:aadonkeyz@gmail.com

0%