探究promise原理

什么是promise

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一

常用的异步编程方案

  • 回调函数
  • 事件监听
  • 发布/订阅(之后文章了解)
  • promise

promise标准

1.Promise 规范有很多,如Promise/A,Promise/B,Promise/D 以及 Promise/A 的升级版 Promise/A+。ES6 中采用了 Promise/A+ 规范,这里了解的也是Promise/A+ 的实现原理。
2.Promise标准解读
在之前一章有了解过promise的状态变化以及基本的使用方法,所以直接略过,直奔主题,了解promise的实现过程

从里到外解剖promise

手动实现promise,需要先了解promise的执行流程以及在流程中调用的方法?

流程分析

fulfilled
rejected
new promise
pendding
resolve
reject
onFulfilled
onRejected
promise
  1. new一个promise实例,瞬间执行(初始状态),状态为pending
  2. new Promise接收一个excutor执行函数,excutor携带连个函数类型参数resolve和 reject
	const promise = new promise((resolve, reject) =>{
			// 异步处理
      		 // 处理结束后、调用resolve 或 reject
	})
  1. 调用resolve,状态由pending --> fulfiled。调用reject,状态由pending --> rejected。注意:一旦状态更改就不能再次发生变化。
function Promise(){
	let that = self // 缓存当前实例
	that.status = 'pending'  // 初始状态
	that.data = undifined //成功时的返回值
	that.reason = undifined //保存失败的原因
	that.onFulfilledCallbacks = []; // 存储fulfilled状态对应的onFulfilled函数,可能有多个
    that.onRejectedCallbacks = []; // 存储rejected状态对应的onRejected函数,可能有多个
    // 成功时调用的方法
    function resolve(value) {
	       if(self.status === 'pending') {
	           self.status = 'resolved';
	           self.data = value;
	           for(var i = 0; i < self.onFulfilledCallbacks.length; i++) {
	               self.onResolvedCallback[i](value);
	           }
	       }
   }
   // 失败时调用的方法
   function reject(reason) {
   		if(self.status === 'pending') {
            self.status = 'rejected';
            self.data = reason;
            for(var i = 0; i < self.onRejectedCallback.length; i++) {
                self.onRejectedCallback[i](reason);
            }
        }
   }
	// executor自执行函数接收的第二个参数为reject函数
	//且reject函数在promise对象状态变为rejected时或executor抛出异常时触发
	try {
	       executor(resolve, reject);
	} catch (e){
	    reject(e);
	}
}
Promise.prototype.then = function (onResolve, onReject) {
    this.onResolvedCallback.push(onResolve);
    this.onRejectedCallback.push(onReject);
};

兴高采烈,试试深浅~~~~妈呀
好像并没有什么卵用?
仔细一看,虎躯一震?当我们在调用then回调之前,resolve已经执行结束了?
在这里插入图片描述

用高大上的语言来表达:
2.2.4规范 onFulfilled 和 onRejected 只允许在 execution context 栈仅包含平台代码时运行.
这里的平台代码指的是引擎、环境以及 promise 的实施代码。实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。

总结一下就是需要将promise的resolve和reject异步执行

修改一下,可以利用setTimeout机制,将resolve中执行回调的逻辑放置到JS任务队列末尾,以保证在resolve执行时,then方法的回调函数已经注册完成.

添加个异步
// 成功时调用的方法
    function resolve(value) {
    	setTimeout(function () {
	       if(self.status === 'pending') {
	           that.status = 'resolved';
	           that.data = value;
	           for(var i = 0; i < self.onFulfilledCallbacks.length; i++) {
	               self.onResolvedCallback[i](value);
	           }
	       }
       },0)
   }
   // 失败时调用的方法
   function reject(reason) {
	   setTimeout(function () {
	   		if(self.status === 'pending') {
	            that.status = 'rejected';
	            that.data = reason;
	            for(var i = 0; i < self.onRejectedCallback.length; i++) {
	                self.onRejectedCallback[i](reason);
	            }
	        }
        },0)
   }

总结:
1.executor函数作为实参在创建Promise对象时传入Promise构造函数。
2.resolve和reject函数作为实参传入executor函数。
3.value作为实参传入resolve和reject函数。
4.promise的resolve和reject需要异步执行

then

Promise/A+ 规范中规定then方法用来注册promise对象状态改变时的回调,且返回一个新的promise对象。而上述代码并没有满足这个规范,那么~~

/**
 * resolve中的值几种情况:
 * 1.普通值
 * 2.promise对象
 * 3.thenable对象/函数
 */

/**
 * 对resolve 进行改造增强 针对resolve中不同值情况 进行处理
 * @param  {promise} promise2 promise1.then方法返回的新的promise对象
 * @param  {[type]} x         promise1中onFulfilled的返回值
 * @param  {[type]} resolve   promise2的resolve方法
 * @param  {[type]} reject    promise2的reject方法
 */

function resolvePromise(promise2, x, resolve, reject) {
    var then
    var thenCalledOrThrow = false

    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise!'))
    }
    if (x instanceof Promise) {
        if (x.status === 'pending') { //because x could resolved by a Promise Object
            x.then(function(v) {
                resolvePromise(promise2, v, resolve, reject)
            }, reject)
        } else { //but if it is resolved, it will never resolved by a Promise Object but a static value;
            x.then(resolve, reject)
        }
        return
    }

    if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
        try {
            then = x.then //because x.then could be a getter
            if (typeof then === 'function') {
                then.call(x, function rs(y) {
                    if (thenCalledOrThrow) return
                    thenCalledOrThrow = true
                    return resolvePromise(promise2, y, resolve, reject)
                }, function rj(r) {
                    if (thenCalledOrThrow) return
                    thenCalledOrThrow = true
                    return reject(r)
                })
            } else {
                	resolve(x)
            	 }
        } catch (e) {
            if (thenCalledOrThrow) return
            thenCalledOrThrow = true
            return reject(e)
        }
    } else {
        resolve(x)
    }
}


Promise.prototype.then = function (onResolved, onRejected) {
  var self = this
    var promise2
    onResolved = typeof onResolved === 'function' ? onResolved : function(v) {
        return v
    }
    onRejected = typeof onRejected === 'function' ? onRejected : function(r) {
        throw r
    }
    //promise对象当前状态为resolved
    if(self.status === 'resolved') {
	 return promise2 = new Promise(function(resolve, reject) {
	            setTimeout(function() { // 异步执行onResolved
	                try {
	                    var x = onResolved(self.data)
	                    resolvePromise(promise2, x, resolve, reject)
	                } catch (reason) {
	                    reject(reason)
	                }
	            })
	        })
    }
    //promise对象当前状态为rejected
	if (self.status === 'rejected') {
        return promise2 = new Promise(function(resolve, reject) {
            setTimeout(function() { // 异步执行onRejected
                try {
                    var x = onRejected(self.data)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (reason) {
                    reject(reason)
                }
            })
        })
    }
    //promise对象当前状态为pending
    //此时并不能确定调用onResolved还是onRejected,需要等当前Promise状态确定。
    //所以需要将callBack放入promise1的回调数组中
   if (self.status === 'pending') {
        return promise2 = new Promise(function(resolve, reject) {
            self.onResolvedCallback.push(function(value) {
                try {
                    var x = onResolved(value)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (r) {
                    reject(r)
                }
            })
            self.onRejectedCallback.push(function(reason) {
                try {
                    var x = onRejected(reason)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (r) {
                    reject(r)
                }
            })
        })
    }
};

完整代码

var Promise = (function() {
    function Promise(resolver) {
        if (typeof resolver !== 'function') { //resolver必须是函数
            throw new TypeError('Promise resolver ' + resolver + ' is not a function')
        }
        if (!(this instanceof Promise)) return new Promise(resolver)

        var self = this //保存this
        self.callbacks = [] //保存onResolve和onReject函数集合
        self.status = 'pending' //当前状态

        function resolve(value) {
            setTimeout(function() { //异步调用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'resolved' //修改状态
                self.data = value

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onResolved(value)
                }
            })
        }

        function reject(reason) {
            setTimeout(function(){ //异步调用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'rejected' //修改状态
                self.data = reason

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onRejected(reason)
                }
            })
        }

        try{
            resolver(resolve, reject) //执行resolver函数
        } catch(e) {
            reject(e)
        }
    }

    function resolvePromise(promise, x, resolve, reject) {
        var then
        var thenCalledOrThrow = false

        if (promise === x) {
            return reject(new TypeError('Chaining cycle detected for promise!'))
        }

        if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
            try {
                then = x.then
                if (typeof then === 'function') {
                    then.call(x, function rs(y) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return resolvePromise(promise, y, resolve, reject)
                    }, function rj(r) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return reject(r)
                    })
                } else {
                    return resolve(x)
                }
            } catch(e) {
                if (thenCalledOrThrow) return
                thenCalledOrThrow = true
                return reject(e)
            }
        } else {
            return resolve(x)
        }
    }

    Promise.prototype.then = function(onResolved, onRejected) {
        //健壮性处理,处理点击穿透
        onResolved = typeof onResolved === 'function' ? onResolved : function(v){return v}
        onRejected = typeof onRejected === 'function' ? onRejected : function(r){throw r}
        var self = this
        var promise2

        //promise状态为resolved
        if (self.status === 'resolved') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //调用then方法的onResolved回调
                        var x = onResolved(self.data)
                        //根据x的值修改promise2的状态
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2状态变为rejected
                        return reject(e)
                    }
                })
            })
        }

        //promise状态为rejected
        if (self.status === 'rejected') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //调用then方法的onReject回调
                        var x = onRejected(self.data)
                        //根据x的值修改promise2的状态
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2状态变为rejected
                        return reject(e)
                    }
                })
            })
        }

        //promise状态为pending
        //需要等待promise的状态改变
        if (self.status === 'pending') {
            return promise2 = new Promise(function(resolve, reject) {
                self.callbacks.push({
                    onResolved: function(value) {
                        try {
                            //调用then方法的onResolved回调
                            var x = onResolved(value)
                            //根据x的值修改promise2的状态
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2状态变为rejected
                            return reject(e)
                        }
                    },
                    onRejected: function(reason) {
                        try {
                            //调用then方法的onResolved回调
                            var x = onRejected(reason)
                            //根据x的值修改promise2的状态
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2状态变为rejected
                            return reject(e)
                        }
                    }
                })
            })
        }
    }

    //获取当前Promise传递的值
    Promise.prototype.valueOf = function() {
        return this.data
    }

    //由then方法实现catch方法
    Promise.prototype.catch = function(onRejected) {
        return this.then(null, onRejected)
    }

    //finally方法
    Promise.prototype.finally = function(fn) {
        return this.then(function(v){
            setTimeout(fn)
            return v
        }, function(r){
            setTimeout(fn)
            throw r
        })
    }

    Promise.prototype.spread = function(fn, onRejected) {
        return this.then(function(values) {
            return fn.apply(null, values)
        }, onRejected)
    }

    Promise.prototype.inject = function(fn, onRejected) {
        return this.then(function(v) {
            return fn.apply(null, fn.toString().match(/\((.*?)\)/)[1].split(',').map(function(key){
                return v[key];
            }))
        }, onRejected)
    }

    Promise.prototype.delay = function(duration) {
        return this.then(function(value) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    resolve(value)
                }, duration)
            })
        }, function(reason) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    reject(reason)
                }, duration)
            })
        })
    }

    Promise.all = function(promises) {
        return new Promise(function(resolve, reject) {
            var resolvedCounter = 0
            var promiseNum = promises.length
            var resolvedValues = new Array(promiseNum)
            for (var i = 0; i < promiseNum; i++) {
                (function(i) {
                    Promise.resolve(promises[i]).then(function(value) {
                        resolvedCounter++
                        resolvedValues[i] = value
                        if (resolvedCounter == promiseNum) {
                            return resolve(resolvedValues)
                        }
                    }, function(reason) {
                        return reject(reason)
                    })
                })(i)
            }
        })
    }

    Promise.race = function(promises) {
        return new Promise(function(resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i]).then(function(value) {
                    return resolve(value)
                }, function(reason) {
                    return reject(reason)
                })
            }
        })
    }

    Promise.resolve = function(value) {
        var promise = new Promise(function(resolve, reject) {
            resolvePromise(promise, value, resolve, reject)
        })
        return promise
    }

    Promise.reject = function(reason) {
        return new Promise(function(resolve, reject) {
            reject(reason)
        })
    }

    Promise.fcall = function(fn){
        // 虽然fn可以接收到上一层then里传来的参数,但是其实是undefined,所以跟没有是一样的,因为resolve没参数啊
        return Promise.resolve().then(fn)
    }

    Promise.done = Promise.stop = function(){
        return new Promise(function(){})
    }

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

    try { // CommonJS compliance
        module.exports = Promise
    } catch(e) {}

    return Promise
})()


参考文章:
Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)
Promise原理与实现

猜你喜欢

转载自blog.csdn.net/duanshilong/article/details/87980019
今日推荐