promise的自定义代码实现

promise的几个关键问题

  1. 如何改变 promise 的状态?

    (1) resolve(value): 如果当前是 pending 就会变为 resolved
    (2) reject(reason): 如果当前是 pending 就会变为 rejected
    (3) 抛出异常: 如果当前是 pending 就会变为 rejected

  2. 一个 promise 指定多个成功/失败回调函数, 都会调用吗?

    当 promise 改变为对应状态时都会调用

  3. 改变 promise 状态和指定回调函数谁先谁后?

    (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    (2) 如何先改状态再指定回调?
    ① 在执行器中直接调用 resolve()/reject()
    ② 延迟更长时间才调用 then()
    (3) 什么时候才能得到数据?
    ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

  4. promise.then()返回的新 promise 的结果状态由什么决定?

    (1) 简单表达: 由 then()指定的回调函数执行的结果决定
    (2) 详细表达:
    ① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
    ② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
    ③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果

  5. promise 如何串连多个操作任务?

    (1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
    (2) 通过 then 的链式调用串连多个同步/异步任务

  6. promise 异常传透?

    (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
    (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理

  7. 如何中断 promise 链?

    (1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
    (2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

  8. then等方法为什么要定义在原型上?

    (1)当方法定义在构造函数内部的this上时,在实例化多个对象的时候,同样的会把方法也会复制一遍(即每个实例化后的对象,都有一个方法),这样的话,当需要该构造函数实例化很多对象的时候,每一个实例化后的对象的方法都要占用一定的内存,这样就会导致内存开销太大了

    (2)而通过prototype来定义的方法,在实例化对象的时候,都只是在每个对象中复制了一个指向该方法的一个指针,所以实际上,占用的内存只有一个方法

    (3)所以对比两者的话,使用prototype来定义方法的话,可以节省很多的内存开销。但是,在构造函数里面,定义的变量有私有变量(即通过var 定义的变量)和公有变量(即通过this来定义的变量),因为私有变量不能被外界访问,所以我们需要有可以在外界访问私有变量的途径,而在构造函数里面通过this定义的方法可以有效的访问私有变量

  9. Promise then中回调为什么是异步执行?

    回调(例如 then 中的)如果可能同步、也可能异步,执行顺序就变成了不确定的,无法保证程序逻辑的一致性 ,也就类似多线程中的竞态条件。为了避免这种不确定性,then 的回调总是作为 Job Queue 中的下一个 Job 执行(异步执行)。

    例如:

    promise.then(function(){ 
      if (trueOrFalse) { 
        // 同步执行 
        foo(); 
      } else { 
        // 异步执行 (如:使用第三方库)
         setTimeout(function(){ 
            foo(); 
         }) 
      } 
    }); 
    
    bar();
    
    1. 如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行? 答案是,如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。

    2. 如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行? 答案一目了然,bar() 先执行,foo() 后执行。

      所以为了保证代码执行顺序的一致性, then 回调必须保证是异步的。

    promise的代码实现

    //Promise是一个构造函数
    //打印原生Promise发现[[PromiseState]],[[PromiseResult]]都是有双中括号的,表明这两个属性都是内置的,外部无法修改的
    
    //executor函数里的内容是同步执行的
    function Promise(executor) {
        //状态值
        this.PromiseState = 'pending';
        //属性值
        this.PromiseResult = null;
    
        //用来保存所有待调用的包含onResolved和onRejected回调函数的对象的数组
        this.callbacks = [];
    
        const self = this;
    
        // function中的this指向window
        function resolve(data) {
            if(self.PromiseState !== 'pending') return;
    
            self.PromiseState = 'fulfilled';
            self.PromiseResult = data;
    
            //异步调用所有待处理的onResolved成功回调函数
            if(self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach(item => {
                        item.onResolved();
                    });
                })
            }
        }
    
        function reject(data) {
            if(self.PromiseState !== 'pending') return;
    
            self.PromiseState = 'fulfilled';
            self.PromiseResult = data;
    
            //异步调用所有待处理的onRejected成功回调函数
            if(self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach(item => {
                        item.onRejected();
                    });
                })
            }
        }
    
        try {
            //同步调用执行器函数
            executor(resolve, reject);
        }catch(e) {
            reject(e);  //异常则直接失败
        }
    }
    
    
    Promise.prototype.then = function(onResolved, onRejected) {
        const self = this;
    
        // 处理异常穿透 
        //当出现异常或者rejected时,虽然then中没有处理rejected的函数,但如果有catch函数,则会一直穿透,交给catch去处理
        if(typeof onRejected !== 'function') {
            onRejected = reason => {
                throw reason;
            }
        }
    
        if(typeof onResolved !== 'function') {
            onResolved = value => value;
        }
        return new Promise((resolve, reject) => {
            function callback(type) {
                try {
                    let result = type(self.PromiseResult);
    
                    if(result instanceof Promise) {
                        // 返回一个新的promise
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        })
                    }else {
                        resolve(result);
                    }
                }catch(e) {
                    reject(e);
                }
            }
            if(this.PromiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved);
                })
            }
        
            if(this.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected);
                })
            }
        
            if(this.PromiseState === 'pending') {
                //将onResolved和onRejected保存起来
                this.callbacks.push({
                    onResolved: function() {
                        callback(onResolved);
                    },
                    onRejected: function() {
                        callback(onRejected);
                    } 
                })
            }
        })
    }
    
    Promise.prototype.catch = function(onRejected) {
        return this.then(undefined, onRejected);
    }
    
    //返回一个成功的 promise 对象 
    Promise.resolve = function(value) {
        return new Promise((resolve, reject) => {
            if(value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            }else {
                resolve(value);
            }
        })
    }
    
    //返回一个失败的 promise 对象
    Promise.reject = function(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        })
    }
    
    // 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败 
    Promise.all = function(promises) {
        return new Promise((resolve, reject) => {
            let count = 0;
            let arr = [];
    
            for(let i=0; i<promises.length; i++) {
                promises[i].then(v => {
                    count++;
                    arr[i] = v;
    
                    //只有所有promise都成功,才返回成功
                    if(count === promises.length) {
                        resolve(arr);
                    }
                }, r => {
                    // 只要有一个失败,就返回失败
                    reject(r);
                })
            }
        })
    }
    
    // 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态 
    Promise.race = function(promises) {
        return new Promise((resolve, reject) => {
            for(let i=0; i<promises.length; i++) {
                promises[i].then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            }
        })
    }
    
上一篇:手写Promise


下一篇:Promise ajax