promise的规范其实种类很多,我们最常用的是promise/A+
这篇文章会先将一个类似于promise的构造函数怎么写,网上很多教程并没有实现A+规范,只是看起来像而已
然后我们深入探究如何一步一步实现真正的promise/A+规范的要求。
首先我们实现一个简单的promise,这个promise类似于express的路由处理
express的路由处理以next的方式一层一层的进入, 直到不再next。这个很像promise呐,也是比较懒,没有去看源码,但试着实现一个那种异步,会发现其实蛮简单的。
ok,废话少说,先搞一个
需求
1. promise拥有then和catch方法
2. promise出错时调用catch,有两种错误,主动跑错可以用next(err)
3. promise的第一个参数为function, 第一个参数为next,其他参数可以传递到下一步。
然后我们要实现的功能如下
new Promise(next => { setTimeout(() => { console.log(1); next(null, 2); }, 1000); }) .then((next, arg) => { setTimeout(() => { console.log(arg); next(); }, 1000); }) .then((next, arg) => { setTimeout(() => { console.log(arg); next(); }, 1000); }) .catch(err => console.error(err));
实现
首先我们实现then和catch方法
我们建立一个回调队列和一个出错回调1
1)then里的东西都会被推进去
2)catch会去替换默认的回调方法
3)next函数会执行resovleCallbacks里的下一个方法
function Promise(execute) { let resolveCallbacks = []; let rejectCallbacks = err => console.error(err); this.then = fn => { resolveCallbacks.push(fn); return this; }; this.catch = fn => { rejectCallback = fn; return this; }; execute(next); function next() { const nextCallback = resolveCallbacks.shift(); nextCallback && nextCallback(next); } }
为了捕捉错误
try { execute(next); } catch (err) { rejectCallback(err); }
我们添加如上的错误捕捉机制
假如果主动跑错就用next(err)
没有出错的话就next(null, arg1, arg2)这样传参
所以我们修改next方法
function next(...args) { if(args[0]){ return rejectCallback(args[0]); }else{ const nextCallback = resolveCallbacks.shift(); try { nextCallback && nextCallback(next, ...args.slice(1)); } catch (err) { rejectCallback(err); } } }
至此就实现完成了,很简单吧
game over
Promise/A+
但事实上一个伟大的promise/A+规范的实现可不止这么简单。
然后我们来看看一个promise/A+规范是什么样子的
1. 状态管理pendding fullfilled(resolved) rejected 三种
2. then返回一个新的promise, then的两个参数是function,是上一步的成功和失败的回调
3. 不同的promise可以接起来使用
以上是主要的规范 更加具体的看这里
要想实现promise/A+,首先要搞清楚它的工作原理
按照规范 最麻烦的是then方法的处理,
但是记住两点就Ok
1. 不同的promise的状态不同,所以then方法不可以返回this,而是应该返回一个新的promise
2. then的执行实在resolve完成后,所以在then方法里把onResolved方法修改为then的第一个参数
3. 在promise中then里的函数如果返回值是promise就必须等到promise执行完成才可以到下一步, 对此我们巧妙的运用promise的then,只要把resolve放到then里边就会延迟resolve的发生
return x.then(resolve);
4. 在promise中then里的函数如果返回值不是promise那就直接执行 然后resolve
5. executor应该是慢一点开始,所以用了setTimeout,因为首先需要执行的是then方法,待一切promise队列就绪后才可以开始。
6. 执行then的时候可能已经resolved了,那么这个时候就立即执行,如果还是pending状态的话那么就放到执行完成的回调函数里。
知道以上几点之后 就可以很轻松的看懂代码了
首先是构造函数
function Promise(executor) { let onResolved = null; let onRejected = null; this.status = 'pending'; let self = this; let resolve = data => { self.data = data || null; self.status = 'resolved'; typeof onResolved === 'function' && onResolved(data); } let reject = (err) => { self.status = 'rejected'; typeof onRejected === 'function' && onRejected(data); } this.then = onResolvedFn => { } executor(resolve, reject); }
然后是then方法
if (self.status === 'pending') { console.log('promise is pending, add callback') return new Promise(resolve => { onResolved = data => { let x = onResolvedFn(self.data) if (x instanceof Promise) { return x.then(resolve); } else { resolve(); } } }) } if (self.status === 'resolved') { console.log('promise is resolved, execuate') return new Promise(resolve => { let x = onResolvedFn(self.data) if (x instanceof Promise) { return x.then(resolve); } else { resolve(); } }) }
then方法实现后,然后我们实现一个Promise.resolve方法
Promise.resolve = data => new Promise(resolve => setTimeout(() => resolve(data)));
关于catch和promise的错误处理机制这里就不详细的写了,反正一切都为了简单看懂。
参考文章: https://zhuanlan.zhihu.com/p/21834559