手写Promise

1,115 阅读3分钟

Promise知识点复习

  • Promise是一种实现异步代码的手段,存储着将来会发生的某种结果。Promise方法接收一个函数参数handler,new一个Promise实例会立即执行这个handler。其中函数handler接收两个方法参数,resolve和reject方法,分别代表执行成功和执行失败的回调函数。用法如下:
const p = new Promise((resolve,reject) => {
    setTimeout(function(){
        resolve('成功')
    },200);
});
p.then(res => console.log(res)); // 成功
  • Promise的then方法,返回一个新的promise实例,因此可以支持链式调用。用法如下:
const p = new Promise((resolve,reject) => {
    setTimeout(function(){
        resolve('成功')
    },200);
});
p.then(res => {
    return res+1;
}).then(data => console.log(data)); // 成功1
  • 如果then方法返回一个新的promise实例,then后的链式调用将等待这个新promise执行完毕后,以这个新promise的返回结果作为参数传入下一个then方法的回调函数中。比如:
const p = new Promise((resolve,reject) => {
    setTimeout(function(){
        resolve('成功')
    },200);
});
p.then(res => {
    return new Promise((resolve,reject)=>{
        resolve(123);
    });
}).then(data => console.log(data)); // 123

例子中p的第一个then方法返回一个新的promise实例,新promise实例执行完毕将123传入下一个then方法的回调函数中,打印出123。

以上是Promise的基本功能,我们手写实现一个Promise,方便理解Promise原理。

手写Promise

1、通过类实现promise:(推荐!)

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class myPromise{
    constructor(handle) {
        this.resolveCallCack = []; // 存储成功时的回调函数
        this.rejectCallCack = []; // 存储失败时的回调函数
        this.value = undefined;
        this.err = undefined;
        this.status = PENDING; // promise的状态

        let resolve = (data) => {
            if(this.status !== PENDING) return;
            this.status = FULFILLED;
            this.value = data;
            this.resolveCallCack.forEach(fn => {
                fn(this.value);
            });
        }

        let reject = (err) => {
            if(this.status !== PENDING) return;
            this.status = REJECTED;
            this.err = err;
            this.rejectCallCack.forEach(fn => {
                fn(tthis.err);
            })
        }

        if(handle instanceof Function){
            handle(resolve,reject);
        }
    }

    then(resolveNext,rejectNext) {
        let that = this;
        return new Promise((resolve,reject) =>{
            switch(this.status){
                case PENDING:
                    this.resolveCallCack.push(resolveNext);
                    this.rejectCallCack.push(resolveNext);
                    break;
                case FULFILLED:
                    resolveNext(this.value);
                    break;
                case REJECTED:
                    rejectNext(this.err);
                    break;
            }
        })
    }
}

var a = new myPromise(function(resolve,rejected) {
    setTimeout(function(){
        resolve("成功");
    },2000);
}).then(data => {
    console.log(data);
})const PENDING = 'pending';

总结:

  • 缺陷:手写的myPromise的then方法中返回一个新promise实例时,执行结果和ES6的Promise存在差异,待完善。

2、通过定义myPromise函数实现promise功能:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function myPromise(handle){
    var self = this; // 先保存一份this,防止后面方法this错乱!!!
    self.status = PENDING;
    self.value = '';
    self.reson = '';
    self.resolvedCallback = [];
    self.rejectedCallback = [];

    function resolve(data){
        if(self.status !== PENDING) return;
        self.status = FULFILLED;
        self.value = data;
        self.resolvedCallback.forEach(fn => {
            fn(self.value);
        });
    }
    function reject(data){
        if(self.status !== PENDING) return;
        self.status = REJECTED;
        self.reson = data;
        self.rejectedCallback.forEach(fn => {
            fn(self.reson);
        });
    }

    try{
        handle(resolve,reject);
    }catch(e){
        reject(e)
    }
}

myPromise.prototype.then = function(resolveNext,rejectNext){
    var that = this;
    return new myPromise((resolve,reject) => {
        switch(that.status){
            case PENDING:
                that.resolvedCallback.push(resolveNext);
                that.rejectedCallback.push(rejectNext);
                break;
            case FULFILLED:
                resolveNext(that.value);
                break;
            case REJECTED:
                rejectNext(that.reson);
                break;
        }
    });
}

myPromise.all = function(arr){
    return new myPromise((resolve,reject)=>{
        var res = [];
        arr.forEach(item => {
            item.then(data => {
                res.push(data);
                if(res.length === arr.length){
                    resolve(res);
                }
            },err=> {
                reject(err);
            })
        });
    });
}

//// 测试myPromise方法
var obj = new myPromise(function(resolve,reject){
     setTimeout(function(){
         resolve(2);
     },0);
}).then((data)=>{
     console.log(data);
})

var obj2 = new myPromise(function(resolve,reject){
     setTimeout(function(){
         resolve(3);
     },0);
}).then((data)=>{
     console.log(data);
})

// 测试myPromise.all方法
var obj = new myPromise(function(resolve,reject){
    setTimeout(function(){
        resolve(2);
    },0);
})

var obj2 = new myPromise(function(resolve,reject){
    setTimeout(function(){
        resolve(3);
    },0);
})
var myall = myPromise.all([obj,obj2]).then(data => {
    console.log("resolve", data);
},err => {
    console.log(err);
});
console.log(myall);

总结:推荐通过类实现promise,如果使用函数实现promise,记得保存一份this防止后边方法访问this错乱。