JS实现Promise原理

promise是用来解决Js中的异步问题的,js中所有的异步可从callback → promise → generator + co = async + await

其实所有的都是callback的变相处理,只是后者慢慢变的越来越优雅和强壮可扩展。

那么如何实现promise呢?先观察一下promise的样子

let  a = new Promise((resolve,reject)=>{
       // dosomething
       resolve()  
})

无非是一个名称叫Promise的对象,然后传参一个函数 (resolve,reject)=>{resolve()}

promise的强大之处在于回调处理,promise.then(resolveFunticon,rejectFunction)

第一个函数是resolve的回调处理函数,第二个是reject

说到resovle,reject,那么还得再提一下pending,promise对象内部有以上三种状态。默认是pending状态

状态的转变需要我们手动自己去调用函数resolve()或者reject()

整理一下思路:new promise的时候callback作为传参参数执行promise函数,callback在promise函数内部执行。callback里手动调用的resolve或者reject方法,那么promise对象里肯定是有这两种方法的。

最关键的是记住状态,然后再then的时候根据状态去判断到底是执行resolveFunticon还是rejectFunction。

function PromiseFn(callBack){
        let self = this;
        self.resolveVal = undefined;
        self.rejectVal = undefined;
        self.status = 'pending'//默认是等待状态
        
        function resolve(val){
            if(self.status === 'pending'){
                self.resolveVal = val;
                self.status = 'resolve'
            }
        }
        function reject(val){
            if(self.status === 'pending'){
                self.rejectVal = val;
                self.status = 'reject'
            }
        }
     //这里要注意,try catch若是写在 let self = this 会报错,let存在暂时死区,没有常规的变量提升。必须先申明后使用
     // callback执行,调用resolve函数。
try{ callBack(resolve,reject)//callback进来自动执行 }catch(e){ reject()//若是有报错,则直接变为reject状态 } }

上面关于let的深入可以去看这篇博客:我用了两个月的时候才理解let

可能会被callback给弄得有点懵,其实把它当做函数fn就行,fn在promise内部执行,然后fn内部刚好有个resolve(),然后再去调用promise的这个resolve执行。

也就是这个原因,所以callback的参数必须是resolve和reject。

上面这一步,需要注意的是callback是立即执行的。下面这段会立即打印111

let  a = new Promise((resolve,reject)=>{
       console.log('111')
})
console.log('456')

上面我们定义了 resolveVal 和 rejectVal,因为待会在promise调用then执行的时候,会作为参数传参给resolveFunticon或者rejectFunction

所以promise对象内部必须记住这个参数。

下面一起看看promise.then吧,promise.then(resolveFunticon,rejectFunction)。在promise的原型链上有个then方法

PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
  let self = this;
  if(self.status === 'resolve'){
	resolveFunction(self.resolveVal)
  }
  if(self.status === 'reject'){
	rejectFunction(self.rejectVal)
  }
}

在then执行的时候,去判断内部是啥状态,然后执行对应的resolve或者reject回调函数。  

然后运行试一试

let promiseA = new PromiseFn((resolve,reject)=>{
         resolve('成功啦')
})
promiseA.then((resolveVal)=>{
	console.log('resolve'+resolveVal)
},(rejectVal)=>{
	console.log('reject'+rejectVal)
})

结果是:  

但是这样就结束了吗?no,我们一般对Promise的使用场景可能是下面这样的,需要考虑异步问题。

let promiseA = new PromiseFn((resolve,reject)=>{
	setTimeout(function(){
		resolve('成功啦')
	},2000)
})

这里用settimeout代替一下,一般我们都是一个ajax请求,然后在请求到结果后去resolve.

上面的写法显然是无法满足这种条件的,当去执行promise.then的时候,发现状态还是pending,不做任何执行。

那我们怎么去做呢?发现状态是pending,肯定是两秒钟之内啦,不妨先把promise.then两个函数参数先在promise里面记下来,两秒钟后状态变为resolve了,再执行函数。

      function PromiseFn(callBack){
		try{
			callBack(resolve,reject)
		}catch(e){
			reject()
		}
		let self = this;
		self.resolveVal = undefined;
		self.rejectVal = undefined;
		self.status = 'pending'//默认是等待状态
		self.keepResolveFn = []//
		self.keepRejectFn = []//
		
		function resolve(val){
			if(self.status === 'pending'){
				self.resolveVal = val;
				self.status = 'resolve';
				self.keepResolveFn.forEach(fn=>fn());
			}
		}
		function reject(val){
			if(self.status === 'pending'){
				self.rejectVal = val;
				self.status = 'reject';
				self.keepRejectFn.forEach(fn=>fn());
			}
		}
		//执行先记录resolve和reject函数事件
		
	}
	PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
		let self = this;
		if(self.status === 'resolve'){
			resolveFunction(self.resolveVal)
		}
		if(self.status === 'reject'){
			rejectFunction(self.rejectVal)
		}
		if(self.status === 'pending'){
			self.keepResolveFn.push(()=>{
				resolveFunction(self.resolveVal);
        	});
        	self.keepRejectFn.push(()=>{
            	rejectFunction(self.rejectVal)
        	});
		}
	}
	let promiseA = new PromiseFn((resolve,reject)=>{
		setTimeout(function(){
			resolve('成功啦')
		},2000)
	})
	promiseA.then((resolveVal)=>{
		console.log('resolve'+resolveVal)
	},(rejectVal)=>{
		console.log('reject'+rejectVal)
	})

结果是:延迟两秒后,打印出  ‘resolve成功啦’。

最后多提一句:所有的then方法执行,也是通过return 一个新的promise对象来执行的。这样才有链式回调,new promise.then().then().then()

        var b = 10;
        new Promise((resolve, reject) => {

            setTimeout(() => {
                b += 10;
                resolve();
//                reject();
            }, 1000);

        }).then(function() {
            console.log(b);
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    b *= 2;
                    resolve();
                }, 1000);
            });
        }).then(function() {
            console.log(b);
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    b *= b;
                    resolve();
                }, 1000);
            });
        }).then(function() {
            console.log(b);
        },function() {
            console.log('失败了');
        });

  

  

 

posted @ 2018-08-16 20:20  萝卜爱吃青菜  阅读(12540)  评论(5编辑  收藏  举报