zoukankan      html  css  js  c++  java
  • Promise的源码实现(符合Promise/A+规范)

    我们手写一个Promise/A+规范,然后安装测试脚本,以求通过这个规范。

    //Promise/A+源代码
    // new Promise时,需要传递一个executor执行器,执行器立即执行
    // executor接受两个参数,分别是resolve和reject
    // promise只能从pending到rejected,或者从pending到fulfilled
    // promise的状态一旦确认,就不会再改变
    // promise有then方法,then接受两个参数,分别是promise成功的回调onFulfilled
    // 和promise失败的回调 onRejected
    // 如果调用then时,promise已经成功,则执行onFulfilled,并将promise值作为参数传递进去
    // 如果promise已经失败,那么执行onRejected并把promise失败的原因作为参数传递进去
    // 如果promise状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再一次将对应的函数执行(发布)
    // then的参数onFulfilled和onRejected可以缺省
    // promise可以then多次,promise的then方法返回一个promise
    // 如果then返回的是一个结果,那么就把这个结果作为参数,传递给下一个then的成功的回调onFulfilled
    // 如果then中抛出了异常,那么就会把这个异常作为参数,传递给下一个失败的回调 onRejected
    // 如果then返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功
    // 就走下一个then的成功,如果失败,就走下一个then的失败
    //pending状态,可以认为是一种中间状态
    const PENDING = 'pending';
    // fullfilled完成状态,可以认为是成功回调了的状态
    const FULFILLED = 'fullfilled';
    // reject即为拒绝状态,即失败的状态
    const REJECTED = 'reject';
    // executor是一个执行器
    function Promise(executor){
    	let self = this;
    	self.status = PENDING;
    	self.onFulfilled = [];//成功的回调
    	self.onRejected = [];//失败的回调
    	// PromiseA+ 2.1
    	function resolve(value){
    		if(self.status === PENDING){
    			self.status = FULFILLED;
    			self.value = value;
    			self.onFulfilled.forEach(fn=>fn());//PromiseA+ 2.2.6.1
    		}
    	}
    	function reject(reason){
    		if(self.status===PENDING){
    			self.status = REJECTED;
    			self.reason = reason;
    			self.onRejected.forEach(fn=>fn());//PromiseA+ 2.2.6.2
    		}
    	}
    	try{
    		executor(resolve,reject)
    	}catch(e){
    		reject(e)
    	}
    }
    // then必须返回一个promise
    Promise.prototype.then = function(onFulfilled,onRejected){
    	// PromiseA+ 2.2.1/PromiseA+ 2.2.5/PromiseA+ 2.2.7.3/PromiseA+2.2.7.4
    	onFulfilled = typeof onFulfilled ==='function'?onFulfilled:value =>value;
    	onRejected = typeof onRejected === 'function'?onRejected:reason=>{throw reason};
    	let self = this;
    	//PromiseA+ 2.2.7
    	let Promise2 = new Promise((resolve,reject)=>{
    		if(self.status===FULFILLED){
    			//PromiseA+2.2.2
    			// Promise A+2.2.4----setTimeout
    			setTimeout(()=>{
    				try{
    					let x = onFulfilled(self.value);
    					resolvePromise(promise2,x,resolve,reject);
    				}catch(e){
    					//PromiseA+2.2.7.2
    					reject(e)
    				}
    			});
    		}else if(self.status === REJECTED){
    			// PromiseA+ 2.2.3
    			setTimeout(()=>{
    				try{
    					let x = onRejected(self.reason);
    					resolvePromise(promise2,x,resolve,reject);
    				}catch(e){
    					reject(e);
    				}
    			})
    		}else if(self.status===PENDING){
    			self.onFulfilled.push(()=>{
    				setTimeout(()=>{
    					try{
    						let x = onFulfilled(self.value);
    						resolvePromise(promise2,x,resolve,reject);
    					}catch(e){
    						reject(e);
    					}
    				});
    			});
    		}
    	});
    	return promise2;
    }
    function resolvePromise(promise2,x,resolve,reject){
    	let self = this;
    	//PromiseA+ 2.3.1
    	if(promise2===x){
    		reject(new TypeError('changing cycle'));
    	}
    	if(x && typeof x ==="object"|| typeof x ==='function'){
    		let used;//PromiseA+ 2.3.3.3.3//只能调用一次
    		try{
    			let then = x.then;
    			if(typeof then === 'function'){
    				//PromiseA+2.3.3
    				then.call(x,(y)=>{
    					// PromiseA+ 2.3.3.1
    					if(used)return;
    					used = true;
    					resolvePromise(promise2,y,resolve,reject);
    				},(r)=>{
    					//PromiseA+2.3.3.2
    					if(used)return;
    					used = true;
    					reject(r)
    				});
    			}else{
    				//PromiseA+ 2.3.3.4
    				if(used)return;
    				used = true;
    				reject(x);
    			}
    		}catch(e){
    			//PromiseA+ 2.3.3.2
    			if(used)return;
    			used = true;
    			reject(e);
    		}
    	}else{
    		//PromiseA+ 2.3.3.4
    		resolve(x);
    	}
    }
    module.exports = Promise;
    
    
    

    我们可以用专门的测试脚本测试所编写的代码是否符合PromiseA+的规范。
    在上面的promise实现的代码中,增加一下代码

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

    安装测试脚本

    npm install -g promises-aplus-tests
    

    如果当前的promise源码的文件名为promise.js

    那么在对应的目录执行以下命令:

    promises-aplus-tests promise.js
    

    promises-aplus-tests中共有872条测试用例。以上代码,可以完美通过所有用例。

    本文借鉴自:https://blog.csdn.net/liuyan19891230/article/details/88385973
    这篇博客是ES6的写法:https://blog.csdn.net/weixin_41436338/article/details/79806033
    有空就多学多看源码,你看那么多人那么牛逼啊

  • 相关阅读:
    git常用命令
    thinkjs框架发布上线PM2管理,静态资源访问配置
    登陆服务器提示“You need to run "nvm install N/A" to install it before using it.”
    CentOS 7.x 用shell增加、删除端口
    CentOS 7.X 安全手记
    Centos 7.x nginx隐藏版本号
    centos7磁盘挂载及取消
    CentOS 7.4上网速度慢,修改DNS!
    Centos7.4 安装Docker
    Nodejs 使用log4js日志
  • 原文地址:https://www.cnblogs.com/smart-girl/p/11158472.html
Copyright © 2011-2022 走看看