不能免俗地贴个Promise标准连接Promises/A+。ES6的Promise有不少方法,包括Promise.all()/Promise.resolve()/Promise.reject()等,但其实这些都是Promises/A+规范以外的,Promises/A+规范只定义了一个Promise.then()方法,这是Promise的核心。git
new Promise((resolve, reject) => { let a = 0; if (a > 1) { resolve(a); } else { reject(a); } }).then(res => { console.log(res); }, err => { console.log(err); })
Promise接收一个函数做为参数,咱们称之为executor,该函数有两个参数resolve和reject,这两个参数也都是函数,而且,它们定义在Promise内部。github
那么咱们定义一个class并定义一个_isFunction方法,用来校验构造函数的参数必须是函数。再定义resolve和reject这两个方法。编程
class MyPromise{ constructor(executor){ if(!this._isFunction(executor)){ throw new Error(`Promise resolver ${executor} is not a function`); } } _isFunction(val){ return Object.prototype.toString.call(val) === '[object Function]'; } _resolve(){ } _reject(){ } }
Promise有三种状态,分别是pending(等待中)、fulfilled(成功)、rejected(失败)。状态改变只能从pending => fulfilled,或者pending => rejected。数组
resolve的做用,就是将Promise的状态从pending改成fulfilled,它接收一个参数做为Promise执行成功的值,这个值会传给then的第一个回调函数。reject的做用是将Promise的状态从pending改成rejected,它也接收一个参数做为Promise执行失败的值,这个值会传给then的第二个回调函数。promise
那么咱们定义好状态_status、_resolve、_reject,再定义两个数组_handleFulfilled、_handleRejected,分别存放then的成功和失败回调集合。当用户调用resolve或reject方法后,开始异步调用_handleFulfilled或_handleRejected数组中的回调。异步
class MyPromise { constructor(executor) { if (!this._isFunction(executor)) { throw new Error(`${executor} is not a function`); } this._status = "pending"; this._value = undefined; this._handleFulfilled = []; this._handleRejected = []; // 不少文章在这里给executor加了try catch,实际上原生Promise的executor中的错误并无捕获 executor(this._resolve.bind(this), this._reject.bind(this)); } _isFunction(val) { return Object.prototype.toString.call(val) === "[object Function]"; } _resolve(value) { if(this._status === 'pending'){ this._status = "fulfilled"; this._value = value; let cb; // 异步按顺序调用并清空回调 setTimeout(() => { while(cb = this._handleFulfilled.shift()){ cb(value); } }, 0) } } _reject(value) { if(this._status === 'pending'){ this._status = "rejected"; this._value = value; let cb; // 异步按顺序调用并清空回调 setTimeout(() => { while ((cb = this._handleRejected.shift())) { cb(value); } }, 0); } } }
Promise.then定义了两个回调onFulfilled和onRejected异步编程
promise.then(onFulfilled, onRejected)
它们分别在Promise执行成功/失败时执行,它们都是可选的,Promises/A+规范规定,若是onFulfilled或onRejected不是函数,将被忽略,Promise会继续执行下一个then的回调。好比下面的例子会输出1,.then(2)则被忽略了。函数
new Promise((resolve, reject) => { resolve(1); }) .then(2) .then((res) => { console.log(res); });
then能够链式调用,是由于每一个then都会返回一个新的Promise。then执行onFulfilled仍是onRejected,取决于Promise的状态,若是Promise状态为pending,只会将onFulfilled和onRejected分别push到_handleFulfilled和_handleRejected数组;若是状态为fulfilled,会执行对应的onFulfilled;若是状态是rejected,执行对应的onRejected;测试
那么then方法的基本结构以下this
then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函数,强制改成函数,而且该函数直接返回接收到的参数,传后面的then的回调函数 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { switch (_status) { case "pending": self._handleFulfilled.push(onFulfilled); self._handleRejected.push(onRejected); break; case "fulfilled": onFulfilled(_value); // todo break; case "rejected": onRejected(_value); // todo break; default: throw new Error('Promise resolver Unverified status'); break; } }); }
在then链式调用的状况下,若是前一个then返回的是一个新Promise,后一个then的回调必须等这个新Promise的状态改变后才会执行。举例,下面的代码输出1以后,等待3秒才会输出2:
new Promise(resolve => { resolve() }).then(() => { return new Promise(resolve => { console.log(1); setTimeout(() => { resolve() }, 3000) }) }).then(() => { console.log(2); })
所以要对then的回调函数的返回值作个判断,若是返回值不是Promise,利用resolve直接返回这个值;若是返回值是Promise,就要等这个Promise状态变化以后再返回,而Promise状态变化以后必定会调用then的回调函数,利用这个特性,将resolve、reject做为then的回调函数便可。
then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函数,强制改成函数,而且该函数直接返回接收到的参数,传后面的then的回调函数 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { const fulfilled = (value) => { const res = onFulfilled(value); if (res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } }; const rejected = (value) => { const res = onRejected(value); if (res instanceof MyPromise) { // 这里是重点 res.then(resolve, reject); } else { reject(res); } }; switch (_status) { case "pending": self._handleFulfilled.push(fulfilled); self._handleRejected.push(rejected); break; case "fulfilled": fulfilled(_value); break; case "rejected": rejected(_value); break; default: throw new Error('Promise resolver Unverified status'); break; } }); }
完整代码
class MyPromise { constructor(executor) { if (!this._isFunction(executor)) { throw new Error(`${executor} is not a function`); } this._status = "pending"; this._value = undefined; this._handleFulfilled = []; this._handleRejected = []; // 不少文章在这里给executor加了try catch,实际上原生Promise的executor中的错误并无捕获 executor(this._resolve.bind(this), this._reject.bind(this)); } _isFunction(val) { return Object.prototype.toString.call(val) === "[object Function]"; } _resolve(value) { if (this._status === "pending") { this._status = "fulfilled"; this._value = value; let cb; // 异步按顺序调用并清空回调 setTimeout(() => { while ((cb = this._handleFulfilled.shift())) { cb(value); } }, 0); } } _reject(value) { if (this._status === "pending") { this._status = "rejected"; this._value = value; let cb; // 异步按顺序调用并清空回调 setTimeout(() => { while ((cb = this._handleRejected.shift())) { cb(value); } }, 0); } } then(onFulfilled, onRejected) { const self = this; const { _value, _status } = this; // 若是onFulfilled、onRejected不是函数,强制改成函数,而且该函数直接返回接收到的参数,传后面的then的回调函数 onFulfilled = self._isFunction(onFulfilled) ? onFulfilled : (v) => v; onRejected = self._isFunction(onRejected) ? onRejected : (v) => v; return new MyPromise((resolve, reject) => { const fulfilled = (value) => { const res = onFulfilled(value); if (res instanceof MyPromise) { res.then(resolve, reject); } else { resolve(res); } }; const rejected = (value) => { const res = onRejected(value); if (res instanceof MyPromise) { // 这里是重点 res.then(resolve, reject); } else { reject(res); } }; switch (_status) { case "pending": self._handleFulfilled.push(fulfilled); self._handleRejected.push(rejected); break; case "fulfilled": fulfilled(_value); break; case "rejected": rejected(_value); break; default: throw new Error('Promise resolver Unverified status'); break; } }); } }
测试一下,先输出1,3秒后输出2,说明MyPromise的基本功能没问题了。
new MyPromise((resolve) => { console.log(1); setTimeout(() => { resolve(2); }, 3000) }).then(res => { console.log(res); })
最后,总结一下,Promise是如何实现异步编程的?
Promise接收一个函数为参数,传入了两个内部的方法resolve和reject,而后用then注册回调函数,手动调用resolve或reject就能够依次执行then的回调,而且给回调函数传值。若是then返回的也是Promise,一样的,手动调用resolve或reject后,才会继续往下执行。
其实本质上仍是回调函数,只不过写法变了。
本文GitHub连接:Promise是如何实现异步编程的?