当前promise实例的决议通过result.then(resolve,reject)被推迟到result返回结果之后,而真正执行时所需要操作的对象和属性,已经通过let that = this与实例进行了绑定 。
很多开发者在这里会觉得非常混乱,很可能是没有意识到每一个promise实例都会生成内部方法resolve( )和reject( ),即时当Promise类实例化的过程结束后,它们依然会被保持在自己的闭包作用域中,在执行栈中涉及到多个处于PENDING状态的promise时,它们的内部方法都是存活的。如果还是觉得抽象,可以利用Chrome的调试工具,将下面的代码逐步执行,并观察右侧调用栈,就可以看到当传入决议函数的是另一个promise时,外层的决议函数都会以闭包的形式继续存在。
let promise1 = new Promise(function(resolve, reject){ setTimeout(function fn1(){ let subpromise = new Promise(function (resolvesub,rejectsub) { setTimeout(function fn2() { resolvesub('value from fn2'); },2000); }); resolve(subpromise); },2000); }); promise1.then(function fn3(res) { console.log(res); }); 七.Promise/A+规范与造车轮指南【Promise/A+规范】:https://github.com/promises-aplus/promises-spec
理清了上面各种情况的基本策略后,我们已经具备了构建一个相对完备的Promise模块的能力。我强烈建议你按照Promise/A+规范来亲自动手实现一下这个模块,你会发现在实现的过程中仍然有大量的代码层面的问题需要解决,但你一定会受益于此。网上有非常多的文章讲述如何根据Promise/A+标准来实现这个库,可是在笔者看来这并不是什么值得炫耀的事情,就好像对照着攻略在打游戏一样。
作为工程师,你既要能够一行一行写出这样一个模块,更要关注规范为什么要那样规定。
【Promise/A+测试套件】: https://github.com/promises-aplus/promises-tests
如果你对照规范的要求写出了这个模块,可以利用官方提供的测试套件(包含800多个测试用例来测试规范中规定的各个细节)来测试自己编写的模块并完善它。javascript语言中都是通过鸭式辩型来检测接口的,无论你是怎样实现规范的各个要求,只要最终通过测试套件的要求即可。如果你依旧觉得心里没谱,也可以参考别人的博文来学习Promise的细节,例如这篇《Promise详解与实现》就给了笔者很大帮助。
八.API以外的视角当越过了语言层面的难点后,推荐你阅读《深入理解Promise五部曲》这个系列的文章。大多数开发者对于Promise的理解和应用都是用来解决回调地狱问题的,而这个系列的文章会让你从另一个角度重新认识Promise,不得不说文章中用发布订阅模式来类比解释Promise的实现机制对于笔者理解Promise提供了巨大的帮助,同时它也能够引发一些通过学习promise/A+规范很难意识到的关于精髓和本质的思考。