全部问题均可以经过加一层中间层来解决。
Promises/A+promise
简易的,不作废话直接开始 :)框架
const p = new Promise((resolve, reject)=>{ // 若是操做成功则调用 resolve 并传入 value // 若是操做失败则调用 reject 并传入 reason });
一般咱们都会使用上述方法获取 Promise 实例:在构造函数种传入一个 executor 方法,当同步/异步的任务完成时调用 resolve,失败时调用 reject,简单易懂,在此很少赘述。异步
一个 Promise 能够理解为一个状态机,相应的 API 接口要么用于改变状态机的状态,要么在到达某个状态时被触发,所以首先须要实现的是 Promise 的状态信息:函数
const PENDING = 0 const FULFILLED = 1 const REJECTED = 2
而且只存在 PENDING => FULFILLED 或者 PENDING => REJECTED 的状态转移。测试
首先实现构造函数的框架以下:this
class Promise { constructor(executor) { this.status = PENDING; // 实例当前的状态 this.data = undefined; // Promise 返回的值 this.defered = []; // 回调函数集 executor(resolve, reject); // 执行 executor 并传入相应的参数 } }
上述代码基本实现 Promise 构造函数的主题部分,可是存在三个问题:code
修修补补以下:对象
class Promise { constructor(executor) { this.status = PENDING; this.data = undefined; this.defered = []; try { // bind, bind, bind! executor(this.resolve.bind(this), this.reject.bind(this)); } catch (e) { this.reject(e); } } resolve(value) { // TODO } reject(reason) { // TODO } }
接下来实现 resolve 和 reject 方法,基本上就是在判断状态为 PENDING 以后把状态改成相应的值,并把对应的 value 和 reason 存在 self 的 data 属性上面,最后执行相应的回调函数,逻辑很简单:接口
resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.data = value; this.defered.forEach(i => i.onfulfiled(value)); } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.data = reason; this.defered.forEach(i => i.onrejected(reason)); } }
Promise 对象有一个 then 方法,用来注册在这个 Promise 状态肯定后的回调,很明显 then 方法须要写在原型链上,Promise 总共有三种可能的状态,在 then 方法中咱们分别用三个判断分支来处理,而且都分别返回一个新的 Promise 实例。事件
then(onResolved, onRejected) { // 若是 then 的参数不是 function 则咱们须要忽略它 onResolved = typeof onResolved === 'function' ? onResolved : function(v) {}; onRejected = typeof onRejected === 'function' ? onRejected : function(r) {}; switch (this.status) { case FULFILLED: return new Promise((resolve, reject) => { // TODO }); case REJECTED: return new Promise((resolve, reject) => { // TODO }); case PENDING: return new Promise((resolve, reject) => { // TODO }); } }
完整的实现以下,其中须要注意的是,若是 onResolved 的返回值是一个 Promise 对象,则直接取它的结果作为新的 Promise 实例的结果:
then(onResolved, onRejected) { onResolved = typeof onResolved === 'function' ? onResolved : function(v) {}; onRejected = typeof onRejected === 'function' ? onRejected : function(r) {}; switch (this.status) { case FULFILLED: return new Promise((resolve, reject) => { try { const r = onResolved(this.data); r instanceof Promise && r.then(resolve, reject); resolve(r); } catch (e) { reject(e); } }); case REJECTED: return new Promise((resolve, reject) => { try { const r = onRejected(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }); case PENDING: return new Promise((resolve, reject) => { const onfulfiled = () => { try { const r = onResolved(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }; const onrejected = () => { try { const r = onRejected(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }; this.defered.push({ onfulfiled, onrejected }); }); } }
至此实现一个简易的 Promise,使用以下测试用例验证:
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }).then((res) => { console.log(res); return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 1000); }); }).then((res) => { console.log(res); return new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 1000); }); }).then((res) => { console.log(res); }); // 1 // 2 // 3 // [Finished in 3.1s]
new Promise((resolve) => { resolve(); }) .then(() => { console.log('1'); }) .then(() => { console.log('2'); }); console.log('3');
执行上面的代码会发现输出的顺序是“1, 2, 3”,而不是正确的“3, 1, 2”,显然是由于咱们没有在 Promise 的 resolve 方法中异步的调用回调函数集致使的,固然解决这个问题也很简单,就是使用 setTimeout,可是这样实现的话并不符合 Promise 在事件循环中的优先级,因此暂时忽略。
new Promise((resolve) => { resolve(8); }) .then() .then() .then((value) => { console.log(value) });
上面的代码使用咱们刚刚实现的 Promise 会打印 undefined,然而这并非咱们指望获得的结果,咱们但愿的是8这个值会穿过两个 then 到达链尾的 then 的执行函数里,其输出应该和这段代码一致:
new Promise((resolve) => { resolve(8); }) .then((value) => { return value; }) .then((value) => { return value; }) .then((value) => { console.log(value); });
其实要实现这个功能十分简单,只要把 then 的两个参数的默认值作简单的修改:
onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v; }; onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r; };