zoukankan      html  css  js  c++  java
  • ES6 Promise 的不完全实现

    一、Promise/A+ 规范

    1.Promise存在三个状态:pending(等待态)、fulfilled(成功态)、rejected(失败态);
    2.pending为初始态,并可以转化为fulfilled和rejected;
    3.成功时,不可转为其他状态,且必须有一个不可改变的值 (value);
    4.失败时,不可转为其他状态,且必须有一个不可改变的原因 (reason);
    5.new Promise(executor = (resolve, reject) => {resolve(value)}), resolve(value)将状态置为 fulfilled;
    6.new Promise(executor = (resolve, reject) => {reject(reason)}), reject(reason)将状态置为 rejected;
    7.如果 executor 执行异常也会 reject();
    8.thenable: then(onFulfilled, onRejected?);
      8.1 onFulfilled: status 为 fulfilled,执行 onFulfilled, 传入 value
      8.2 onRejected: status 为 rejected, 执行 onRejected

    二、同步 Promise

    同步 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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    // 1.Promise存在三个状态:pending(等待态)、fulfilled(成功态)、rejected(失败态)
    const STATUS_PENDING = 'pending'
    const STATUS_FULFILLED = 'fulfilled'
    const STATUS_REJECTED = 'rejected'
    class myPromise {
        constructor(executor) {
            // pending为初始态,并可以转化为fulfilled和rejected
            this.status = STATUS_PENDING
            this.value = '' // 3
            this.reason = '' // 4
     
            let resolve = value => {
                // 5.
                if (this.status === STATUS_PENDING) {
                    this.status = STATUS_FULFILLED
                    this.value = value
                }
            }
            let reject = reason => {
                //6.
                if (this.status === STATUS_PENDING) {
                    this.status = STATUS_REJECTED
                    this.reason = reason
                }
            }
            // 7.
            try {
                executor(resolve, reject);
            catch (err) {
                reject(err);
            }
        }
      // 8.
        then(onFulfilled = () => {}, onRejected = () => {}) {
            // 8.1
            if (this.status === STATUS_FULFILLED) {
                onFulfilled(this.value)
            }
            // 8.2
            if (this.status === STATUS_REJECTED) {
                onRejected(this.reason)
            }
        }
    }
     
     
    let ps = new myPromise(resolve => {
        console.log('before resolve')
        resolve(1)
    })
    ps.then(res => {
        console.log(res)
    })
     
    let pe = new myPromise((resolve, reject) => {
        console.log('before reject')
        reject('reject error')
    })
    pe.then(res => {
        console.log(res)
    }, error => {
        console.log(error)
    })

    在上面的两个例子中,所有任务的执行都是同步的,可以与接下来的异步 promise 的执行顺序对比下。

    三、异步 Promise

    先放下我们的运行实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let pa = new myPromise(resolve => {
        console.log('before resolve')
        setTimeout(()=>{
            resolve(1)
        },1000)
    })
    pa.then(res => {
        console.log(res)
    })

     在这里,我们的 executor 函数体中有异步的代码块,那么在执行 executor(resolve, reject); 的时候,setTimeout中的任务就会被推入异步执行栈中,等待主线程中的宏任务(详见 EventLoop in Js)全部计算完成再执行这个任务,因此,我们打断点会发现,  then() 的执行会早于  resolve(1) , 而在 then() 执行的时候,pa.status 依然是 pending,接下啦根据逻辑判断 then 函数执行完成退出,然后执行异步任务,整个代码执行完毕,故控制台只会打印出 'before resolve'。
    明白了这里的执行顺序,我们即可以进行完善,代码如下:(标记 改 A)

    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    const STATUE_PENDING = 'pending';
    const STATUE_FULFILLED = 'fulfilled';
    const STATUS_REJECTED = 'rejected';
     
    class MyPromise {
        constructor(executor) {
            // pending 是初始态,并可以转化成 fulfilled 和 rejected
            this.status = STATUE_PENDING;
            this.value = ''// 3.
            this.reason = ''// 4.
     
            // 改 A start
            // 存放成功的数组
            this.onResolvedCallbacks = [];
            // 存放失败的数组
            this.onRejectedCallbacks = [];
            // 改 A end
     
            let resolve = value => {
                // 5.
                if (this.status === STATUE_PENDING) {
                    this.status = STATUE_FULFILLED;
                    this.value = value;
     
                    // 改 A start
                    // 成功之后的执行栈,
                    this.onResolvedCallbacks.forEach(fn => fn());
                    // 改 A end
                }
            }
             
            let reject = reason =>  {
                // 6.
                if (this.status === STATUE_PENDING) {
                    this.status = STATUS_REJECTED;
                    this.reason = reason;
     
                    // 改 A start
                    // 成功之后的执行栈,
                    this.onRejectedCallbacks.forEach(fn => fn());
                    // 改 A end
                }
            }
     
     
            // 7.
            try {
                executor(resolve, reject);
            catch (error) {
                reject(err);
            }
        }
     
        // 8
        then(onFulfilled = () => {}, onRejected = () => {}){
            // 8.1
            if (this.status === STATUE_FULFILLED) onFulfilled(this.value);
            // 8.2
            if (this.status === STATUS_REJECTED) onRejected(this.reason);
     
            // 改 A start
            // 如果是处于异步任务的
            if (this.status === STATUE_PENDING) {
                // 推入相应的执行栈
                this.onResolvedCallbacks.push(() => onFulfilled(this.value));
                this.onRejectedCallbacks.push(() => onRejected(this.reason));
            }
            // 改 A end
        }
    }

    为什么要分析下这边的执行顺序,一来复习下 EventLoop,二来对下面的链式调用的理解比较重要(这里也是打断点才发现的,推翻了一直以来对 Promise.then 的理解,之前一直认为 executor 中的异步任务执行完了才真正的去执行 then 函数和里面的onFulfilled/onRejected 函数)。

    四、new Promise().then().then()... 链式调用

    Promise 的链式调用和 jquery 的链式调用是不同的,在 jquery 或者一些其他的三方包中,我们在函数末尾加上 returnthis  即可实现,所以这里无论链多少,都是在同一个对象上做文章。而 Promise 的每一次(链式)调用,其都会产生一个新的 Promise 对象, 并基于这个新的 Promise 调用 then 函数,虽然我们写的时候是.then().then()...。 首先我们来看实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    let pc = new MyPromise((resolve, reject) => {
        console.log(0);
        setTimeout(() => {
            resolve(1);
        }, 3000);
    })
    pc.then(res => {
        console.log(res);
     
        return new MyPromise(resolve => {
            console.log(2);
            setTimeout(() => {
                resolve(3)
            }, 3000);
        })
    }).then(res => {
        console.log(res);
    })

    注意下结构,我们在第一个 then 的参数函数中会有一个新的 Promise 返回。
    然后是 MyPromise 类:

    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    const STATUE_PENDING = 'pending';
    const STATUE_FULFILLED = 'fulfilled';
    const STATUS_REJECTED = 'rejected';
     
    function resolvePromise(promise2, x, resolve, reject) {
        // 处理循环引用报错
        if (x === promise2) {
            // reject 报错
            return reject(new TypeError('chaining cycle detected for promise'));
        }
     
        // 记录, 防止多次调用
        let called;
     
        // x 是对象(不包括 null)或者函数
        if (x != null && (typeof x === 'object' || typeof x === 'function')) {
            try {
                // A+ 规定,声明 then = x 的 then 方法
                let then = x.then;
                // then 是 function,则默认是 promise
                if (typeof then === 'function') {
                    // 就让 then 执行, 第一个参数是 this, 后面是成功的回调和失败的回调
     
                    then.call(x, y => {
                        // 成功和失败只能调用一个
                        if (called) return;
                        called = true;
     
                        // resolve 的结果依旧是promise 那就继续解析
                        resolvePromise(promise2, y, resolve, reject);
                    }, err => {
                        // 成功和失败只能调用一个
                        if (called) return;
                        called = true;
     
                        // 失败,停止继续调用
                        reject(err);
                    })
                else {// 不是的话直接 resolve 即可
                    resolve(x);
                }
     
            catch (error) {
                // 出错,即失败
                if (called) return;
                called = true;
     
                // 取 then 出错了那就不继续了
                reject(error);
            }
        else {
            resolve(x);
        }
    }
     
    class MyPromise {
        constructor(executor) {
            this.status = STATUE_PENDING;
            this.value = '';
            this.reason = '';
     
     
            this.onResolvedCallbacks = [];
            this.onRejectedCallbacks = [];
     
            let resolve = value => {
                if (this.status === STATUE_PENDING) {
                    this.status = STATUE_FULFILLED;
                    this.value = value;
     
                    this.onResolvedCallbacks.forEach(fn => fn());
                }
            }
             
            let reject = reason =>  {
                if (this.status === STATUE_PENDING) {
                    this.status = STATUS_REJECTED;
                    this.reason = reason;
     
                    this.onRejectedCallbacks.forEach(fn => fn());
                }
            }
     
            try {
                executor(resolve, reject);
            catch (error) {
                reject(err);
            }
        }
     
        then(onFulfilled, onRejected){
            // onFulfilled 不是函数, 则忽略,直接返回 value
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
            // onRejected 不是函数, 则忽略,直接扔出错误
            onRejected = typeof onRejected === 'function' ? onRejected : err => {
                throw err;
            };
     
            let promise2 = new MyPromise((resolve, reject) => {
                if (this.status === STATUE_FULFILLED) {
                    // 推一个异步任务
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);   
                        catch (error) {
                            reject(error)
                        }
                    }, 0);
                }
     
                if (this.status === STATUS_REJECTED) {
                    // 推一个异步任务
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);   
                        catch (error) {
                            reject(error)
                        }
                    }, 0);
                }
     
                if (this.status === STATUE_PENDING) {
                    // 推到执行栈中
                    this.onResolvedCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onFulfilled(this.value);
                                resolvePromise(promise2, x, resolve, reject);   
                            catch (error) {
                                reject(error)
                            }
                        }, 0);
                    });
     
                    this.onRejectedCallbacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onRejected(this.reason);
                                resolvePromise(promise2, x, resolve, reject);   
                            catch (error) {
                                reject(error)
                            }
                        }, 0);
                    })
                }
     
            });
     
            return promise2;
        }
    }

    这里要注意的是 then 函数的执行会产生一个新的 Promise, 第一个 then 函数的参数函数的执行也会产生一个新的 Promise。

    五、其他:catch、resolve、reject、race和all

    这里除 catch 外其余均是静态方法:

     1. catch(特殊的 then 方法):

    1
    2
    3
    catch(fn){
        return this.then(null,fn)
    }

     2.reslove(resolve 一个值)

    1
    MyPromise.resolve = val => new Promise(resolve=> resolve(val))

     3.reject(reject 一个值)

    1
    MyPromise.reject = val => new Promise((resolve,reject)=> reject(val))

     4.race Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

    1
    2
    3
    4
    5
    MyPromise.race = promises => {
        return new MyPromise((resolve, reject) =>
            promises.forEach(pro => pro.then(resolve, reject))
        )
    }

     5.all Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

    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
    MyPromise.all = function (promises) {
        return new Promise((resolve, reject) => {
            let index = 0;
            let result = [];
            if (promises.length === 0) {
                resolve(result);
            else {
                function processValue(i, data) {
                    result[i] = data;
                    if (++index === promises.length) {
                        resolve(result);
                    }
                }
                for (let i = 0; i < promises.length; i++) {
                    //promises[i] 可能是普通值
                    Promise.resolve(promises[i]).then((data) => {
                        processValue(i, data);
                    }, (err) => {
                        reject(err);
                        return;
                    });
                }
            }
        });
    }
  • 相关阅读:
    MySQL DDL 在指定位置新增字段
    .NET平台常见技术框架整理汇总
    使用Linq求和方法Sum计算集合中多个元素和时应该注意的性能问题
    python时间操作
    django 利用原生sql操作数据库
    滑动验证码获取像素偏移量
    python opencv简单使用
    django通过旧数据库库生成models
    pandas 操作csv文件
    简单工厂模式(Simple Factory Pattern)
  • 原文地址:https://www.cnblogs.com/yjf713/p/13460692.html
Copyright © 2011-2022 走看看