zoukankan      html  css  js  c++  java
  • javaScript系列 [41]Promise源码实现

    本文介绍参考[PromiseA+]规范来实现一个符合规范的Promise库。

    上面是ES6+实现的Promise核心方法,其整体结构也可以通过下面的打印查看

      /* 01-打印Promise类的内容(静态方法) */
      console.dir(Promise)
    
      /* 打印输出(已经省略部分内容) */
      // length: 1                      期望形参数量((resolve,reject)=>{})
      // name: "Promise"                类(构造函数)的名字
      // prototype: Promise             原型对象
      //    then: ƒ then()              then处理函数
      //    catch: ƒ catch()            catch处理函数
      //    finally: ƒ finally()        完成的处理函数
      //    constructor: ƒ Promise()    原型的构造器属性
      // race: ƒ race()                 异步任务并发先执行完
      // reject: ƒ reject()             包装为reject     
      // resolve: ƒ resolve()           包装为resolve
      // all: ƒ all()                   异步任务并发都执行完
      // allSettled: ƒ allSettled()
      // Symbol(Symbol.species): (...)
      // Symbol(Symbol.toStringTag): "Promise"
    

    Promises/A+ 规范约定的Promise的实现逻辑和核心代码。

    /* 核心注解 */
    /* 1、Promise应该被设计为一个类(构造函数) */
    /* 2、Promise存在三种状态,分别是pending(等待)、rejected(失败) 和 resolved(成功)。*/
    /* 3、Promise类(构造函数)接收一个“拥有两个函数参数的函数”作为参数,我们可以称之为执行器函数(executor)立即执行。*/
    /* 4、Promise类(构造函数)内部应该以私有函数的方式来是实现reject和resolve函数。 */
    /* 5、Promise内部考虑到异步任务的执行(譬如定时器)Promise状态无法立即完成等待->成功|失败的切换,使用注册/订阅模式*/
    /* 6、Promise的then方法处理失败、成功、等待态(如果存在异步任务)的Promise后续任务。 */
    /* 7、Promise的then方法应该实现链式调用,实现的策略是总是返回一个新的Promise对象 */
    
    const PENDING = "PENDING";
    const RESOLVED = "RESOLVED";
    const REJECTED = "REJECTED";
    
    function resolvePromise(promise, x, resolve, reject) {
    
        /* 1、死循环处理 */
        if (promise === x) {
            reject(new TypeError("# Chaining cycle detected for promise #<Promise>"))
        }
    
        let called = false;
        /* 2、区分返回值是基本值和(Promise)的情况*/
        if ((typeof x === "object" && x != null) || typeof x === "function") {
            try {
                let then = x.then;
                if (typeof then === "function") {
                    then.call(x, y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise, y, resolve, reject); /* 递归调用 */
                    }, r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    })
                } else {
                    resolve(x);
                }
            } catch (e) {
                if (called) return;
                called = true;
                reject(e);
            }
        } else {
            resolve(x);
        }
    }
    
    class Promise {
        constructor(executor) {
            this.status = PENDING;
            this.value = this.reason = undefined;
            this.rejectedCallBacks = [];
            this.resolvedCallBacks = [];
    
            /* reject 和 resolve 应该被实现为私有函数 */
            let resolve = (val) => {
    
                if (val instanceof Promise) {
                    return val.then(resolve, reject);
                }
    
                if (this.status === PENDING) {
                    this.status = RESOLVED;
                    this.value = val;
                    this.resolvedCallBacks.forEach(fn => fn());
                }
            }
    
            let reject = (val) => {
                if (this.status === PENDING) {
                    this.status = REJECTED;
                    this.reason = val;
                    this.rejectedCallBacks.forEach(fn => fn());
                }
            }
    
            /* 执行器函数应该立即执行,并进行异常处理 */
            try {
                executor(resolve, reject);
            } catch (e) {
                reject(e);
            }
        }
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
            onRejected = typeof onRejected === "function" ? onRejected : e => { throw e }
    
            let promise = new Promise((resolve, reject) => {
                if (this.status === RESOLVED) {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
    
                }
    
                if (this.status === REJECTED) {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                }
    
                if (this.status === PENDING) {
                    this.rejectedCallBacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onRejected(this.reason);
                                resolvePromise(promise, x, resolve, reject);
                            } catch (e) {
                                reject(e);
                            }
                        }, 0);
                    })
    
                    this.resolvedCallBacks.push(() => {
                        setTimeout(() => {
                            try {
                                let x = onFulfilled(this.value);
                                resolvePromise(promise, x, resolve, reject);
                            } catch (e) {
                                reject(e);
                            }
                        }, 0);
                    })
                }
            })
            return promise;
        }
    }
    
    /* 基准测试 */
    Promise.defer = Promise.deferred = function() {
        let dfd = {};
        dfd.promise = new Promise((resolve, reject) => {
            dfd.resolve = resolve;
            dfd.reject = reject;
        })
        return dfd;
    }
    
    module.exports = Promise;
    
    

    规范基准测试

    npm install promises-aplus-tests g
    cd dist
    promises-aplus-tests Promise.js
    

    Promise还有一些诸如catch和resolve等方法,下面简单给出它们的实现代码。

    class Promise{
        /* .... */
        catch (errCallBack) {
            return this.then(null, errCallBack); /* 为了支持链式调用,此处需要return */
        }
        static resolve(data) {
            return new Promise((resolve, reject) => {
                resolve(data)
            })
        }
        static reject(err) {
            return new Promise((resolve, reject) => {
                reject(err);
            })
        }
        finally(callBack) {
            return this.then((value) => {
                return Promise.resolve(callBack()).then(() => value);
            }, reason => {
                return Promise.resolve(callBack()).then(() => { throw reason });
            })
        }
    }
    
    
  • 相关阅读:
    Jpa 一对多级联查询 排序设置
    Spring Data Jpa Specification 调用Oracle 函数/方法
    Spring boot 集成 阿里 Mqtt
    将Jquery序列化后的表单值转换成Json
    Linux安装和卸载MySQL5.7
    NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{3bFuKD5MTOWOCfJ1ZFrfdw}{192.168.0.105}{192.168.0.105:9301}]]
    Docker下安装RabbitMQ
    JAVA数据结构与算法-稀疏数组
    第一篇博客
    测试用例编写方法:边界值分析方法
  • 原文地址:https://www.cnblogs.com/wendingding/p/15760945.html
Copyright © 2011-2022 走看看