自己实现ES6中的Promise API

Promise API是ES6的推荐标准,该API是由各JavaScript的执行引擎在底层,通常是使用C++语言实现的

为了更好地理解Promise API的使用方法并探究其可能的实现方式,笔者在JavaScript层面对Promise API进行了实现。

该实现只是作为实验、学习使用,虽然与内置的实现功能相同,但是在设计和运行效率上肯定是不能相提并论。

我也希望之后能对自己的实现进行改善。

该实现在处理异步任务时,采用了轮询的方式来检测其状态的变化。

具体代码如下(注:笔者采用Node方式进行模块定义,需要时可以通过Browserify等工具处理成浏览器可用的版本):

"use strict";

const STATUS_PENDING = 'pending',
      STATUS_FULFILLED = 'fulfilled',
      STATUS_REJECTED = 'rejected';

const POLL_INTERVAL = 200;

function JSPromise(executor){

    if(!executor || typeof executor != 'function'){
	throw "No executor specified for this promise!";
    }

    var _this = this;

    this.promiseStatus = STATUS_PENDING;
    this.resolved = false;
    this.promiseValue = undefined;
    this.rejectReason = undefined;
    this.onFulfilled = undefined;
    this.onRejected = undefined;

    function resolve(value){
	_this.promiseValue = value;
	_this.promiseStatus = STATUS_FULFILLED;
    }

    function reject(reason){
	_this.rejectReason = reason;
	_this.promiseStatus = STATUS_REJECTED;
    }

    executor.apply(this, [resolve, reject]);
};

JSPromise.resolve = function(value){
    return new JSPromise(function(resolve, reject){
	resolve(value);
    });
};

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

JSPromise.prototype.then = function(onFulfilled, onRejected){
    if(this.resolved ||
	(!onFulfilled && !onRejected) ||
	 (typeof onFulfilled != 'function' && typeof onRejected != 'function')){
	return JSPromise.resolve(undefined);
    }

    const _this = this;
    this.onFulfilled = (onFulfilled && typeof onFulfilled == 'function')?onFulfilled: this.onFulfilled;
    this.onRejected = (onRejected && typeof onRejected == 'function')?onRejected: this.onRejected;
    
    if(this.promiseStatus === STATUS_FULFILLED){
	this.resolved = true;
	if(!this.onFulfilled){
	    return JSPromise.resolve();
	}
	let retVal = this.onFulfilled.apply(this, [this.promiseValue]);
	if(retVal instanceof JSPromise){
	    return retVal;
	}else{
	    return JSPromise.resolve(retVal);
	}
    }
    
    if(this.promiseStatus === STATUS_REJECTED){
	this.resolved = true;
	if(!this.onRejected){
	    return JSPromise.reject(this.rejectReason);
	}
	let retVal = this.onRejected.apply(this, [this.rejectReason]);
	if(retVal instanceof JSPromise){
	    return retVal;
	}else{
	    return JSPromise.resolve(retVal);
	}
    }

    if(this.promiseStatus === STATUS_PENDING){
	const _this = this;
	return new JSPromise(function (resolve, reject){
	    setTimeout(function checkStatus(){
		if(_this.resolved){
		    resolve();
		}else if(_this.promiseStatus === STATUS_FULFILLED && _this.onFulfilled){
		    _this.resolved = true;
		    let retVal = _this.onFulfilled.apply(_this, [_this.promiseValue]);
		    if(retVal instanceof JSPromise){
			retVal.then(function(value){
			    resolve(value);
			});
		    }else{
			resolve(retVal);
		    }
		}else if(_this.promiseStatus === STATUS_REJECTED){
		    if(_this.onRejected){
			_this.resolved = true;
			let retVal = _this.onRejected.apply(_this, [_this.rejectReason]);
			if(retVal instanceof JSPromise){
			    retVal.then(function(value){
				resolve(value);
			    });
			}else{
			    resolve(retVal);
			}
		    }else{
			reject(_this.rejectReason);
		    }
		}else if(_this.promiseStatus === STATUS_PENDING){
		    setTimeout(function(){
			checkStatus(resolve, reject);
		    }, POLL_INTERVAL);
		}else{
		    _this.resolved = true;
		    resolve();
		}
	    }, 0);
	});
    }

    throw new Error("Unexpected status: "+_this.promiseStatus);
};

JSPromise.prototype.catch = function(onRejected){
    if(this.resolved){
	return JSPromise.resolve();
    }

    if(!onRejected || typeof onRejected != 'function'){
	throw "Must specify an 'onRejected' callback function as the argument!";
    }
    
    return this.then(undefined, onRejected);
};

module.exports = JSPromise;

 

欢迎批评指正,相互探讨。

本实验的源码和测试代码放置于github:https://github.com/waychan23/promise-js-impl。

posted @ 2017-04-04 21:42  waychan23  阅读(242)  评论(0编辑  收藏  举报