Promises
其中的一种模式就是promise,它代表了一种潜在地、长时间运行但不必返回完成操作的结果。与阻塞并长时间等待运行计算完成不同,这种模式返回一个代表承诺(promised)结果的对象。
例如,需要创建一个请求到第三方系统,而它的网络延迟是不确定的。应用程序可以被释放出来做其他事情,直到这个请求返回值需要使用到,而不是在等待并阻塞住整个程序。Pormise实现了一种方法,即为状态的变化注册相应的回调函数,通常命名为then方法。
var results = searchTwitter(term).then(filterResults);displayResults(results);
在任何时刻,promise只可能处于三种状态之一:unfulfilled(未完成), resolved(已解决) or rejected(拒绝)。
为了说明这些概念是如何工作的,我们可以了解下标准,这个标准在流行的库中已经有了许多衍生工具。在promise对象中的then方法为resolved以及rejected状态添加了处理程序。then函数会返回另外一个promise对象以便形成promise管道,使开发人员能够将异步操作串联起来,这样第一个操作的结果就可以作为参数传入到第二个中了。
then(resolvedHandler, rejectedHandler);
函数resolvedHandler回调函数会在promise对象进入完成状态时调用,并传递计算(computation)出来的结果。而rejectedHandler函数会在promise对象进入拒绝状态时被调用。
可以用promise的伪代码来重现上面的示例,主要包含创建一个Ajax请求用于搜索Twitter、用数据填充屏幕以及处理错误。为了更好的理解实现方法,我们尝试着从零开始构建一个promise模式的框架。我们以一个例子开始,即如果我们从头开始设计一个仅包含基础功能的promise库应该有什么,首先,我们需要一些对象格式来保存promise。
var Promise = function () { /* initialize promise */};
接下来,我们需要实现then方法,允许我们根据promise的状态变化将操作串联在一起。这个方法包含两个函数参数,用于处理promise被解决以及promise被拒绝的情况。
Promise.prototype.then = function (onResolved, onRejected) { /* invoke handlers based upon state transition */};
我们也需要一对方法来处理未完成和已解决或者未完成和已拒绝之间的状态转换。
Promise.prototype.resolve = function (value) { /* move from unfulfilled to resolved */};Promise.prototype.reject = function (error) { /* move from unfulfilled to rejected */};
对于一个promise对于应该是什么样,现在我们已经搭建的差不多了。我们可以继续上面的示例,获取包含IE10标签的tweets。首先,我们通过使用XMLHttpRequest2创建一个方法来发送一个Ajax Get请求到一个给定的URL,并且将它封装成一个promise。接下来,我们将特别为Twitter创建一个方法,用来调用含有给定搜索条件的Ajax封装方法。最后,我们会调用我们的搜索函数并在无序列表中展示结果。
function searchTwitter(term) { var url, xhr, results, promise; url = 'http://search.twitter.com/search.json?rpp=100&q=' + term; promise = new Promise(); xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function (e) { if (this.status === 200) { results = JSON.parse(this.responseText); promise.resolve(results); } }; xhr.onerror = function (e) { promise.reject(e); }; xhr.send(); return promise;}function loadTweets() { var container = document.getElementById('container'); searchTwitter('#IE10').then(function (data) { data.results.forEach(function (tweet) { var el = document.createElement('li'); el.innerText = tweet.text; container.appendChild(el); }); }, handleError);}
到目前为止,我们可以把promise模式应用于单个Ajax请求,那么接下来讨论另一种场景——我们想要发送超过一个Ajax请求并协调它们的结果。为了处理这种场景,我们会在我们的Promise对象中创造一个when方法,用来储存被调用的promise对象。一旦promise从unfulfilled转变成resolved或者rejected,then方法里对应的处理函数就会被调用。有个场景至关重要,即when方法需要等待所有操作都完成才能继续。
Promise.when = function () { /* handle promises arguments and queue each */};
现在我们可以同时存储多个promise,以在Twitter上搜索IE10和IE9两个标签的内容为例。
var container, promise1, promise2;container = document.getElementById('container');promise1 = searchTwitter('#IE10');promise2 = searchTwitter('#IE9');Promise.when(promise1, promise2).then(function (data1, data2) { /* Reshuffle due to date */ var totalResults = concatResults(data1.results, data2.results); totalResults.forEach(function (tweet) { var el = document.createElement('li'); el.innerText = tweet.text; container.appendChild(el); });}, handleError);
要重点记住的是,在这些例子中的代码除了普通JavaScript代码,并没有其它特别的。Web开发人员必定会创造他们自己的类Promise库;但为了方便和一致性,你可以利用在一般JavaScript库中公开的promise模式。
原文:
https://github.com/pingan1927/translate/blob/master/Asynchronous%20Programming%20in%20JavaScript%20with%20%E2%80%9CPromises%E2%80%9D.md
JQuery AJAX deferred :
http://api.jquery.com/category/deferred-object/