promise-await-yield 异步三连

JavaScript 中使用异步的情况非常多, 因为 js 采取单线程, 如果某段代码处理时间过长, 后面的代码将一直等待其执行完毕。
由此产生的处理方案是, 任务队列与事件循环(event loop), 无论是最初的回调函数(并非只用在异步), 还是后面解决 callback hell 而出现的 promise 等, 都是依靠在这个机制上的。

主线程遇到异步函数时, 将其扔给异步模块, 继续执行主线程中剩下的部分, 当异步函数满足了执行要求时, 将回调函数放入任务队列中, 主线程完成后, 才会从任务队列中选择任务执行, 而 event loop 负责的是不断从任务队列中取代码, 详细请看 - JavaScript 异步、栈、事件循环、任务队列

历史演变情况

易嵌套的 callback -> promise -> 包装 promise 的 generator -> generator 的语法糖 await

promise

基础概念

JS里一个promise可以有以下几种基本状态:
1.nothing happened yet
2."locked in" to another promise
3.fulfilled
4.rejected
其中{1,2}为pending,{3,4}为settled,{2,3,4}为resolved,{1}为unresolved。详细可以看 Promise的fulfill和resolve

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。Promise 的参数 executor 函数在 Promise 构造函数返回所建 Promise 实例对象前被调用, 当异步成功完成并调用 resolve 函数时, 将会将 Promise 的状态 [[PromiseState]] 更改为 fulfilled (chrome 中是 resolved), 如果没有调用 resolve 将一直是 pending 状态
Promise 状态
结果值 是 Promise 内置伪属性 internal slots [[PromiseValue]] (chrome devtool 将它暴露出来了), 它将作为参数传入 之后 then 的参数 onFulfilled 或 onRejected 中

基础使用

下方新构建一个 Promise 的对象, 当执行到 resolve 时, 将 [[PromiseState]] 改为 fulfilled, 当 Promise 变成接受状态(fulfilled)时调用 then 中的 onFulfilled。onFulfilled 有一个参数,即接受的最终结果

1
2
3
4
5
6
7
var p = new Promise(function(resolve, reject){
setTimeout(function(){
resolve(123);
}, 50);
});
p.`then`((data)=>console.log(data))
console.log(p)

then

每次调用 then 后都会返回一个 promise 对象, 返回的情况由 then 中的回调决定, 描述一些常用的情况

  1. 返回了一个值, 那么 then 返回的 Promise 将会是 fulfilled 并且将返回的值作为下一个 then 的 onFulfilled 的参数
  2. 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的, 并且状态与该 Promise 保持一致, 并依据该 Promise 中的 resolve 和 reject 来使用下一个 then 的两个参数

    详细情况请看 Promise.prototype.then()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var p = new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve(123)
    }, 1000)
    })
    p.then(res => {
    return '456'
    }).then(res => {
    console.log(res) //打印 456
    })

简单 Promise 实现

当然这都是口头上的执行流程, 现在来写一个看看

  1. 结构

    1
    2
    3
    4
    class promise{
    constructor(){}
    then(){}
    }
  2. 构造函数

    !!!! 如果不将 then 中的 onFulfilled 函数使用setTimeout 推迟到下个事件循环再执行, 执行顺序会与原生Promise不同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    constructor(executor){
    //初始状态
    this._states = 'pending';
    this._internalValue = undefined;
    // 添加回调函数队列
    this._chain = []
    const resolve = (res)=>{
    this._states = 'fulfilled';
    this._internalValue = res;
    //如果此时已经有 then 被调用了
    for(var {onFulfilled} of this._chain){
    //对象结构赋值, chain 中元素都是对象
    setTimeout(() => onFulfilled(res), 0);
    }
    }
    const reject = (err)=>{
    this._states = 'rejected';
    this._internalValue = err;
    for(var {onRejected} of this._chain){
    setTimeout(() => onRejected(res), 0);
    }
    }
    executor(resolve, reject);
    }
  3. then 函数编写

    如果已经 settled 那就执行, 否则加入执行队列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    then(onFulfilled, onRejected) {
    if (this._states === 'fulfilled') {
    onFulfilled(this._internalValue)
    } else if (this._state === 'rejected') {
    onRejected(this._internalValue)
    } else {
    this._chain.push({ onFulfilled, onRejected })
    }
    }
  4. Promise 调用链

    then() 应该返回一个新 Promise

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    then(onFulfilled, onRejected) {
    var self = this
    return new promise((resolve, reject) => {
    // 确保在 onFulfilled() 和 onRejected() 的错误将导致返回的 promise 失败(reject)
    const _onFulfilled = (res) => {
    resolve(onFulfilled(res));
    };
    const _onRejected = (err) => {
    reject(onRejected(err));
    };
    console.log(self === this) //。。。。
    if (this._state === 'fulfilled') {
    _onFulfilled(this._internalValue);
    } else if (this._state === 'rejected') {
    _onRejected(this._internalValue);
    } else {
    this._chian.push({ onFulfilled: _onFulfilled, onRejected: _onRejected });
    }
    });
    }

onFulfilled() 返回 Promise 的话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const resolve = res => {
if (this._state !== 'pending') {
return
}
// 如果 res 是 thenable(带有then方法的对象, 如 Promise)
// 必须判断 res 不是null 或 undefined 否则跳到 reject 去处理了
if (res&&typeof res.then === 'function') {
return res.then(resolve, reject)
}

this._state = 'fulfilled'
this._internalValue = res
for (const { onFulfilled } of this._chain) {
setTimeout(() => onFulfilled(res), 0);
}
return res
}

!!!! 建议写一段代码, 在脑海中运行一遍, debug 也可以, 实在不行纸上写一遍流程(最佳方案), 这玩意调用来调用去, 脑袋都绕晕了, 可以在下方看看测试对比, 输出可以点击网站左下角的 console 按钮看到

### generator (可能搭在await里) ### await (待写-水平还要再高点, Promise 就够吃力了, 肯定会补的)

参考文章:
Write Your Own Node.js Promise Library from Scratch

Promise

文章作者:
文章链接: https://luckyray-fan.github.io/2019/10/20/promise-await-yield/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 luckyray