1. JavaScript 基础

  2. 函数进阶

  3. 深入数据和类型

  4. 运算符

  5. 浏览器存储

  6. Document

  7. Web API

  8. 事件

  9. 错误处理

  10. 异步编程

  11. 网络请求

  12. 模块

  13. 练习

  14. 实例

  15. 工具与规范

async、await

async 与 await 是两个关键字,能让我们用同步的写法来写异步的程序。

async

async 关键字用于函数前面,它能使用函数返回的的值变成一个 promise:

$$jsdemo$$
$$edit$$
async function func() {
    return "三眼鸭"
}

let promise = func()
console.log(promise)

它与以下的代码是等价的:

$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
    resolve("三眼鸭")
})

console.log(promise)

单单是这样并不能体现 async 的作用, async 需要搭配 await 使用才能起到效果。

await

await 关键字表示等待 promise 执行完成并得到执行结果, await 只能在 async 函数中使用。

let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("三眼鸭")
    }, 3000)
})

async function func() {
    let result = await promise
    alert(result) // 三眼鸭,等待执行完成
    alert("执行完毕") // 执行完毕
}

func()

await 并不意味着会阻塞 JavaScript 的主线程的执行, 它阻塞的只是 async 函数的执行。

$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("三眼鸭")
    }, 3000)
})

async function func() {
    let result = await promise
    alert(result) // 三眼鸭,等待执行完成
    alert("执行完毕") // 执行完毕
}

func()

alert("END") // 最先执行

async、await 的好处

asyncawait 最大的好处就是让我们用同步的思维去写异步的程序。

假设我们有以下代码,要下载一个文件,这个文件的下载链接包含在 A 文件当中,而 A 文件的下载链接包含在 B 中, B 又包含在 C 中。

那么我们要依次下载 C → B → A → 最终文件,那么代码就得写成以下这样:

$$jsdemo$$
$$edit$$
function download() {
    // 这个下载花费 2 秒钟
    return new Promise((resolve, reject) => {
        let file = "我是文件哦"
        setTimeout(() => resolve(file), 2000)
    })
}

console.log("开始执行了~")
console.log("先去下个文件~")

// 下载好了通知我就行,不等你了
download().then((file) => {
    console.log("下载 C 完成")
    console.log("拿到 B 的链接")
    download().then((file) => {
        console.log("下载 B 完成")
        console.log("拿到 A 的链接")
        download().then((file) => {
            console.log("下载 A 完成")
            console.log("拿到 最终文件 的链接")
            download().then((file) => {
                console.log("下载 最终文件 完成")
            })
        })
    })
})

console.log("做其他事情去了~")

我们会陷入回调地狱中,回调越写越多,代码执行顺序越来越混乱。

那么就可以使用 asnycawait 改写我们的程序了:

$$jsdemo$$
$$edit$$
function download() {
    // 这个下载花费 2 秒钟

    return new Promise((resolve, reject) => {
        let file = "我是文件哦"
        setTimeout(() => resolve(file), 5000)
    })
}

async function getFile() {
    let file = await download()
    console.log("下载 C 完成")
    console.log("拿到 B 的链接")

    file = await download()
    console.log("下载 B 完成")
    console.log("拿到 A 的链接")

    file = await download()
    console.log("下载 A 完成")
    console.log("拿到 最终文件 的链接")

    file = await download()
    console.log("下载 A 完成")
    console.log("下载 最终文件 完成")
}

console.log("开始执行了~")
console.log("先去下个文件~")

getFile()

console.log("做其他事情去了~")

错误处理

await 返回的是 resolve 的结果,如果是 reject 则会抛出一个错误,我们需要处理这个错误的话则需要使用 try ... catch

$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
        reject(new Error("三眼鸭"))
    }, 3000)
})

async function func() {
    try {
        let result = await promise // throw new Error("三眼鸭")
        alert(result)
        alert("执行完毕")
    } catch (error) {
        alert(error) // Error: 三眼鸭
    }
}

func()