Promise 解析

Promise

由于js的语言特性(用户交互)和工作环境(浏览器脚本),决定了它是单线程工作,所以两段脚本不能同时运行,但为了实现功能,所以人们使用了事件和回调来初步解决这个问题,例如(addEventListener),但这也带来了严重的回调问题,非常容易陷入回调地狱的困恼,

由于这个问题。js发展至今,社区提出了promise(承若)标准,被es6写入了语言标准中,统一了它的用法,并在原生中提供了标准的Promise对象

让我们先来实例化一个标准的promise对象:

    //实例化一个promise对象,这个对象有两个参数(resolve-决定,reject-拒绝)
    let promise = new Promise((resolve,reject)=>{
        //延时3s,把promise的状态改为resolve-决定
        setTimeout(function(){
            resolve('666')
        },3000)
    })
    //每个实例都有then()方法,用来获取其值或原因。
    //then(onFulfilled, onRejected)
    //成功的回调,失败的回调
    promise.then(data=>{
        console.log(data)
    },err=>{
        console.error(err)
    }).then()

同时promise还可以多次调用then()方法,也可以在resolve中继续抛出一个新的promise 例:

    promise.then(function(data){
        console.log('data2=',data);
    },function(err){
        console.log('err2=',err);
    });

或者:

    let promise2 = promise.then(function(data){
      return new Promise(function(resolve,reject){
        setTimeout(function(){
          resolve(data + '777' );
        },1000);
      });
    });

当然还有常见的all(),catch(),resolve(),reject()等等一些方法,而这些方法都是按照Promise/A+规范规定的 (详情

我们现在就按照这个规范来实现一个属于我们自己的promise

首先我们先定义出这个类:

// executor是一个执行函数,在实例化的时候被传入。这个函数会执行两个被传入的状态函数
var Promise = function (executor) { 
    let self = this;
    //没个promise都会有个初始化值,这个值在规范中叫做pending
    self.status = 'pending';
    self.value = undefined; // 默认成功的值
    self.reason = undefined; // 默认失败的原因
    self.onResolvedCallbacks = []; // 存放then成功的回调
    self.onRejectedCallbacks = []; // 存放then失败的回调
    // 成功状态要执行的函数
    function resolve(value) {
        //更改他的状态值,为成功,且不能更改
        if (self.status === 'pending') {
            self.status = 'resolved';
            self.value = value;
            //实例多次调用then(),循环释放数组
            self.onResolvedCallbacks.forEach(function (fn) {
                fn();
            });
        }
    }
    // 失败状态要执行的函数
    function reject(reason) {
        //更改他的状态值,为失败,且不能更改
        if (self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
            //实例多次调用then(),循环释放数组
            self.onRejectedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }
    如果直接传入错误的代码,那么直接进入reject
    try {
        executor(resolve, reject)
    } catch (e) {
        // 捕获的时候发生异常,就直接失败了
        reject(e);
    }
}

下面我们来实现then()方法,个方法每个实例都有,他是一个方法,所以我们把它挂载到Promise原型上:

Promise.prototype.then = function (onFulfilled, onRjected) {
    //成功和失败默认一个函数,防止报错,
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
        return value;
    }
    onRjected = typeof onRjected === 'function' ? onRjected : function (err) {
        throw err;
    }
    let self = this;
    //定义一个返回的promise
    let promise2;
    //当状态是成功的时候,可能会在函数中再次返回一个promise
    if (self.status === 'resolved') {
        promise2 = new Promise(function (resolve, reject) {
            // 当成功或者失败执行时有异常那么返回的promise应该处于失败状态
            //这个x  是第一个promise执行后的结果
            // x可能是一个promise 也有可能是一个普通的值
            setTimeout(function () {
                try {
                    let x = onFulfilled(self.value);
                    // x可能是别人promise,写一个方法统一处理
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })
        })
    }
    //当状态是失败的时候
    if (self.status === 'rejected') {
        promise2 = new Promise(function (resolve, reject) {
            setTimeout(function () {
                try {
                    let x = onRjected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })

        })
    }
    // 当调用then时可能没成功 也没失败
    if (self.status === 'pending') {
        promise2 = new Promise(function (resolve, reject) {
            // 此时没有resolve 也没有reject
            self.onResolvedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                })
            });
            self.onRejectedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onRjected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            });
        })
    }
    return promise2;
}

集中处理x

function resolvePromise(promise2, x, resolve, reject) {
    // 有可能这里返回的x是别人的promise
    // 先跑错
    if (promise2 === x) { //这里应该报一个类型错误,有问题
        return reject(new TypeError('循环引用了'))
    }
    // 看x是不是一个promise,promise应该是一个对象
    let called; // 表示是否调用过成功或者失败
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        //根据语法规定的几种情况来判断
        // 可能是promise {},看这个对象中是否有then方法,如果有then我就认为他是promise了
        try {
            let then = x.then;
            if (typeof then === 'function') {
                // 成功
                then.call(x, function (y) {
                    if (called) return
                    called = true
                    // y可能还是一个promise,在去解析直到返回的是一个普通值
                    //递归调用这个函数,
                    resolvePromise(promise2, y, resolve, reject)
                }, function (err) { //失败
                    if (called) return
                    called = true
                    reject(err);
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e);
        }
    } else { // 说明是一个普通值1
        resolve(x); // 表示成功了
    }
}

在实现了这些之后,其他的方法,更多的就是一个语法糖,我们来实现他们
catch:

扫描二维码关注公众号,回复: 5602458 查看本文章
    catch实际上就是reject,所以一般建议在then里面不穿reject(),而链式调用catch方法
    Promise.prototype.catch = function (callback) {
        return this.then(null, callback)
    }

all

//会传入一个数组,这个数组是promise集合
Promise.all = function (promises) {
    return new Promise(function (resolve, reject) {
        //arr是最终返回值的结果
        let arr = []; 
        // 表示成功了多少次
        let i = 0; 
        function processData(index, y) {
            arr[index] = y;
            if (++i === promises.length) {
                resolve(arr);
            }
        }
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(function (y) {
                processData(i, y)
            }, reject)
        }
    })
}

race

//race就是赛跑的意思,谁获取结果比较快,就返回谁
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
Promise.race = function (promises) {
    return new Promise(function (resolve, reject) {
        for (var i = 0; i < promises.length; i++) {
            promises[i].then(resolve,reject)
        }
    })
}
// 生成一个成功的promise
Promise.resolve = function(value){
    return new Promise(function(resolve,reject){
        resolve(value);
    })
}
// 生成一个失败的promise
Promise.reject = function(reason){
    return new Promise(function(resolve,reject){
        reject(reason);
    })
}

defer 延期处理
会包容promise 可用于封装在传递方法之外调用原有的promise回调

Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise(function (resolve, reject) {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd
}

猜你喜欢

转载自www.cnblogs.com/oicb/p/10568151.html