手写Promise A+规范

320 阅读3分钟

前言:用过Promise的前端小伙伴都应该对它的API语法很熟悉了,这里我就不详细说了,我们直接上代码吧!

  • 1.首先我们知道在new Promise创建一个新实例的时候,如果什么都不传的时候会报错的 那么我们首先做一个参数合法校验。
function Promise(executor) {
	// 参数合法校验
    if (typeof executor !== "function") {
    	throw new TypeError("Promise resolve " + executor + " is not a function");
    }
}
  • 2.我们知道promise有3个状态,fulfilled(成功),rejected(失败),pending(等待态).一旦状态成功就不能失败,一旦失败就不可能成功,当状态为等待态的时候,可能成功,也可能失败。
  • 3.每一个Promise实例我们一般常用的有3个方法,then,catch,all 下面我们将一个简单的Promise框架搭成这个样子
function Promise(executor) {
	// 参数合法校验
    if (typeof executor !== "function") {
    	throw new TypeError("Promise resolve " + executor + " is not a function");
    }
    // 设置实例的私有属性
    this.PromiseStatus = "pending"; // 初始状态下设置该Promise的状态为等待态
    this.PromiseValue = undefined;
    // 设定传递给executor并且执行可以修改实例状态和value的resolve/reject的函数
    // new Promise的时候会立即把executor这个函数执行
    // executor函数执行出现错误,也会把实例的状态改为失败,且value是失败的原因
    try {
      executor(function resolve(value) {
      },function reject(reason) {
      });
    } catch (err) {
    	reject(err.message);
    } 
}
// 定义在Promise原型上的方法是共有属性
Promise.prototype.then = function () {}
Promise.prototype.catch = function () {}
new Promise(function (resolve,reject){
	reject(100);
});

我们的框架就这么搭好啦哈哈哈哈!

我们来写一个公共方法来修改实例的状态和值

// 修改实例的状态和值,将方法中的this改为实例,只有当前状态为pending才能修改状态
    var _this = this;
    function change(status,value) {
        if (_this.PromiseStatus !=== "pending") return;
        _this.PromiseStatus = status;
        _this.PromiseValue = value;
    }
    try {
      executor(function resolve(value) {
          change("fulfilled",value);
      },function reject(reason) {
      	  change("rejected",reason);
      });
    } catch (err) {
        change("rejected",err.message);
    }
  • 接下来我们new一个Promise实例,就可以实现一个简单Promise效果
    // 在浏览器里面试试,返回一个rejecyed状态,值为100
    var p1 = new Promise(function (resolve,reject){
        reject(100);
    });

下面来思考一下then方法

p1.then(function (value) {
	console.log("OK",value);
},function (reason) {
	console.log("NO",reason);
});
console,log(p1);
// 我们发现我们手写的Promise确实把状态和值改掉了,但是没有执行.then这个方法

我们需要通知.then的方法执行后才去执行resolve/reject方法,这里我们先要注入.then方法

this.resolveFunc = function() {};
this.rejectFunc = function() {};
function change(status,value) {
    if (_this.PromiseStatus !=== "pending") return;
    _this.PromiseStatus = status;
    _this.PromiseValue = value;
    //注入.then方法(异步的)
    var delayTimer = setTimeout(function () {
        clearTimeout(delayTimer);
        delayTimer = null;
        var status = _this.PromiseStatus,value = _this.PromiseValue;
        status === "fulfilled"?_this.resolveFunc.call(_this,value) : 
            _this.rejectFunc.call(_this,value);
    },0);
}
Promise.prototype.then = function (resolveFunc,rejectFunc) {
    this.resolveFunc = resolveFunc;
    this.rejectFunc = rejectFunc;
}

下面我们来优化一下.then这个方法

  • .then 这个方法可以穿一个函数,也可以传两个函数。传一个函数就把成功或者失败的函数顺延到下一个.then的方法里。
Promise.prototype.then = function (resolveFunc,rejectFunc) {
    // 参数不传默认值的处理,实现状态的顺延
    if (typeof resolveFunc !== "function") {
       resolveFunc = function(value) {
           return Promise.resolve(value); // 返回一个成功的顺延
       }
    }
    if (typeof rejectFunc !== "function") {
        rejectFunc = function(reason) {
           return Promise.reject(reason); // 返回一个失败的顺延
       }
    }
    var _this = this;
    // this.resolveFunc = resolveFunc;
    // this.rejectFunc = rejectFunc;
    // 返回一个新的Promise实例
    return new Promise(function (resolve,reject) {
        // 我们返回的新实例的成功和失败
        _this.resolveFunc = function (value) {
            try {
                var x = resolveFunc.call(_this,value);
                x instanceof Promise?x.then(resolve,reject):resolve(x);
            } catch (err) {
                reject(err.message);
            }  
        }
        _this.rejectFunc = function (reason) {
            try {
                var x = rejectFunc.call(_this,reason);
                x instanceof Promise?x.then(resolve,reject):resolve(x); // 只要执行不报错,返回的都是成功
            } catch (err) {
                reject(err.message);
            }  
        }
    });
}
// 把Promise当做一个对象,在这个对象上写这两个方法
Promise.resolve = function (value) {
    return new Promise(function(resolve) {
        resolve(value);
    });
}
Promise.reject = function () {
	return new Promise(function(_,reject) {
        reject(reason);
    });
}

接着写.catch方法

Promise.prototype.catch = function (rejectFunc) {
    return this.then(null,rejectFunc);
}

接着写.all方法

Promise.all = function(promiseArr) {
    return new Promise(function(resolve, reject) {
        var index = 0, values = [];
        for (var i = 0;i < promiseArr.length; i++) {
            // 利用闭包的方式保存循环的每一项索引
            (function (i) {
                var item = promiseArr[i];
                // 当前项不是Promise,直接当成成功项
                !(item instanceof Promise)?item=Promise.resolve(item):null;
                // 如果当前项是Promise
                item.then(function (value) {
                    index++;
                    values[i] = value;
                    if (index >= promiseArr.length) {
                        resolve(values); // 所有的实例都是成功的
                    }
                }).catch(function (reason) {
                    // 一个失败,全部失败
                    reject(reason);
                });
            })(i);
        }
    })
}  

到这里,最简单的Promise是实现了。End~^_^