并发(concurrency)和 并行(parallelism)区别

并发: 至少两个线程同时处理中,可以看作广义的并行或虚拟并行。

并行: 至少2个线程同时执行

代码实现

定义2个异步函数

function fp1() {
    return new Promise((r) => {
        setTimeout(() => {
            r('')
        }, 1000)
    })
}

function fp2() {
    return new Promise((r) => {
        setTimeout(() => {
            r('')
        }, 3000)
    })
}

串行实现

async function ss() {
    await fp1()
    await fp2()

    // 等效实现
    fp1().then(() => {
        fp2().then()
    })
}

并发实现

async function cc() {
    const p1 = fp1()
    const p2 = fp2()
    await p1
    await p2

    // 等效实现
    await Promise.all([fp1(), fp2()])
}

await 关键字使得当前函数执行被暂停,直到 promise settles 并且返回结果。

在 ES 规范上没查到这种实现方式的直观描述,可能是浏览器自身行为。

await 可以使用Thenable对象

class Thenable {
    constructor() {}
    then(r) {
        setTimeout(() => r(''), 1000)
    }
}

async await 并发缺点

1、对 reject 状态不正常捕获

promise 链不是一次就构建好的,而是分阶段构造的,因为控制是先后从 async 函数获取和返回的。

例如,在下面代码中,即使在 promise 链中进一步配置了 .catch 方法处理,也会抛出一个未处理的 promise rejection 错误。这是因为 p2 直到控制从 p1 返回后才会连接到 promise 链。

async function fn() {
    const p1 = new Promise((r) => {
        setTimeout(() => r(''), 3000)
    })
    const p2 = new Promise((undefined, rej) => {
        setTimeout(() => rej('rej'), 1000)
    })
    await p1
    await p2
}
// 不能正常捕获rej
fn().catch(console.log)