本博文转至:http://www.csdn.net/article/2014-05-28/2819979-JavaScript-Promisehtml
【编者按】JavaScript是一种基于对象和事件驱动并具备相对安全性的客户端脚本语言。自推出后就大受开发者的青睐,基于JavaScript的开发工具也不可胜数,开发者们能够灵活选择,轻松构建应用。原文做者TAT.dmyang就JavaScript中的Promise规范给出了一些看法,目前高级浏览器如Chrome、Firefox都已经内置了Promise对象,提供更多的操做接口,如此优雅的Promise具有哪些特性呢?且看下文:前端
一直以来,JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深刻人心。在设计API的时候,不论是浏览器厂商仍是SDK开发商亦或是各类类库的做者,基本上都已经遵循着callback的套路。html5
近几年随着JavaScript开发模式的逐渐成熟,CommonJS规范顺势而生,其中就包括提出了Promise规范,Promise彻底改变了js异步编程的写法,让异步编程变得十分的易于理解。node
在callback的模型里边,咱们假设须要执行一个异步队列,代码看起来可能像这样:jquery
1 loadImg('a.jpg', function() { 2 loadImg('b.jpg', function() { 3 loadImg('c.jpg', function() { 4 console.log('all done!'); 5 }); 6 }); 7 });
这也就是咱们常说的回调金字塔,当异步的任务不少的时候,维护大量的callback将是一场灾难。当今Node.js大热,好像不少团队都要用它来作点东西以沾沾“洋气”,曾经跟一个运维的同窗聊天,他们也是打算使用Node.js作一些事情,但是一想到js的层层回调就望而却步。git
好,扯淡完毕,下面进入正题。es6
Promise可能你们都不陌生,由于Promise规范已经出来好一段时间了,同时Promise也已经归入了ES6,并且高版本的chrome、firefox浏览器都已经原生实现了Promise,只不过和现现在流行的类Promise类库相比少些API。github
所谓Promise,字面上能够理解为“承诺”,就是说A调用B,B返回一个“承诺”给A,而后A就能够在写计划的时候这么写:当B返回结果给个人时候,A执行方案S1,反之若是B由于什么缘由没有给到A想要的结果,那么A执行应急方案S2,这样一来,全部的潜在风险都在A的可控范围以内了。ajax
上面这句话,翻译成代码相似:chrome
1 var resB = B(); 2 var runA = function() { 3 resB.then(execS1, execS2); 4 }; 5 runA();
只看上面这行代码,好像看不出什么特别之处。但现实状况可能比这个复杂许多,A要完成一件事,可能要依赖不止B一我的的响应,可能须要同时向多我的询问,当收到全部的应答以后再执行下一步的方案。最终翻译成代码可能像这样:
在这里,当每个被询问者作出不符合预期的应答时都用了不一样的处理机制。事实上,Promise规范没有要求这样作,你甚至能够不作任何的处理(即不传入then的第二个参数)或者统一处理。
好了,下面咱们来认识下Promise/A+规范:
then
方法(能够说,then就是promise的核心),并且then必须返回一个promise,同一个promise的then能够调用屡次,而且回调的执行顺序跟它们被定义时的顺序一致能够看到,Promise规范的内容并不算多,你们能够试着本身实现如下Promise。
如下是笔者本身在参考许多类Promise库以后简单实现的一个Promise,代码请移步promiseA。
简单分析下思路:
构造函数Promise接受一个函数resolver
,能够理解为传入一个异步任务,resolver接受两个参数,一个是成功时的回调,一个是失败时的回调,这两参数和经过then传入的参数是对等的。
其次是then的实现,因为Promise要求then必须返回一个promise,因此在then调用的时候会新生成一个promise,挂在当前promise的_next
上,同一个promise屡次调用都只会返回以前生成的_next
。
因为then方法接受的两个参数都是可选的,并且类型也没限制,能够是函数,也能够是一个具体的值,还能够是另外一个promise。下面是then的具体实现:
这里,then作了简化,其余promise类库的实现比这个要复杂得多,同时功能也更多,好比还有第三个参数——notify,表示promise当前的进度,这在设计文件上传等时颇有用。对then的各类参数的处理是最复杂的部分,有兴趣的同窗能够参看其余类Promise库的实现。
在then的基础上,应该还须要至少两个方法,分别是完成promise的状态从pending到resolved或rejected的转换,同时执行相应的回调队列,即resolve()
和reject()
方法。
到此,一个简单的promise就设计完成了,下面简单实现下两个promise化的函数:
因为Promise构造函数接受一个异步任务做为参数,因此getImg
还能够这样调用:
接下来(见证奇迹的时刻),假设有一个BT的需求要这么实现:异步获取一个json配置,解析json数据拿到里边的图片,而后按顺序队列加载图片,没张图片加载时给个loading效果
这里的sleep只是为了看效果加的,可猛击查看demo!固然,Node.js的例子可查看这里。
在这里,Promise.resolve(v)
静态方法只是简单返回一个以v为确定结果的promise,v可不传入,也能够是一个函数或者是一个包含then
方法的对象或函数(即thenable)。
相似的静态方法还有Promise.cast(promise)
,生成一个以promise为确定结果的promise;
Promise.reject(reason)
,生成一个以reason为否认结果的promise。
咱们实际的使用场景可能很复杂,每每须要多个异步的任务穿插执行,并行或者串行同在。这时候,能够对Promise进行各类扩展,好比实现Promise.all()
,接受promises队列并等待他们完成再继续,再好比Promise.any()
,promises队列中有任何一个处于完成态时即触发下一步操做。
可参考html5rocks的这篇文章JavaScript Promises,目前高级浏览器如Chrome、Firefox都已经内置了Promise对象,提供更多的操做接口,好比Promise.all()
,支持传入一个promises数组,当全部promises都完成时执行then,还有就是更加友好强大的异常捕获,应对平常的异步编程,应该足够了。
现今流行的各大js库,几乎都不一样程度的实现了Promise,如dojo,jQuery、Zepto、when.js、Q等,只是暴露出来的大都是Deferred
对象,以jQuery(Zepto相似)为例,实现上面的getImg()
:
固然,jQuery中,不少的操做都返回的是Deferred或promise,如animate
、ajax
:
jQuery还实现了done()
和fail()
方法,其实都是then方法的shortcut。
处理promises队列,jQuery实现的是$.when()
方法,用法和Promise.all()
相似。
其余类库,这里值得一提的是when.js,自己代码很少,完整实现Promise,同时支持browser和Node.js,并且提供更加丰富的API,是个不错的选择。这里限于篇幅,再也不展开。
咱们看到,无论Promise实现怎么复杂,可是它的用法却很简单,组织的代码很清晰,今后不用再受callback的折磨了。
最后,Promise是如此的优雅!但Promise也只是解决了回调的深层嵌套的问题,真正简化JavaScript异步编程的仍是Generator,在Node.js端,建议考虑Generator。
本博文转至:http://www.csdn.net/article/2014-05-28/2819979-JavaScript-Promise