偏偏只有这两种状态呢?
这样设计Promise,其主要原因是程序员一直都在跟二进制打交道。我们这些码农非常清楚如何把1 和0 揉捏起来建成令人瞠目的逻辑之塔。Promise 如此强大的一个主要原因是,它允许我们把任务当成布尔量来处理。
Promise 对象的逻辑合并技术有一个最常见的用例:判定一组异步任务何时完成。假设我们正在播放一段演示视频,同时又在加载服务器上的一个游戏。我们希望这两件事一旦结束(对次序没有要求),就马上启动游戏。
- 演示视频已经播放完毕。
- 游戏已经加载完毕。
这两个进程各用一个Promise 对象来表示,我们的任务就是在这两个Promise 均已执行时启动游戏。我们如何做到这一点呢?
下面隆重介绍jQuery 的when 方法!
var gameReadying = $.when(tutorialPromise, gameLoadedPromise); gameReadying.done(startGame);when 相当于Promise 执行情况的逻辑与运算符(AND)。一旦给定的所有Promise 均已执行,就立即执行when 方法产生的Promise 对象;或者,一旦给定的任意一个Promise 被拒绝,就立即拒绝when 产生的Promise。
when 方法的绝佳用例是合并多重Ajax 调用。假设需要马上进行两次post 调用,而且要在这两次调用都成功时收到通知,这时就无需再为每次调用请求分别定义一个回调。
$.when($.post('/1', data1), $.post('/2', data2)) .then(onPosted, onFailure);调用成功时,when 可以访问下辖的各个成员Promise 对象的回调参数,不过这么做很复杂。这些回调参数会当作参数列表进行传递,传递的次序和成员Promise 对象传递给when 方法时一样。如果某个成员Promise 对象提供多个回调参数,则这些参数会先转换成数组。
因此,要想根据赋予$.when 方法的所有成员Promise 对象获得全部回调参数,可能会写出像下面这样的代码(但笔者并不推荐这么做)。
$.when(promise1, promise2) .done(function(promise1Args, promise2Args) { // ... });在这个例子中,如果执行promise1 时用到了一个参数'complete',执行promise2 时用到了3 个参数(1、2、3),则promise1Args 就是字符串'complete',promise2Args 就是数组[1,2,3]。
虽然有可能,但如果不是绝对必要,我们不应该自行解析when 回调的参数,相反应该直接向那些传递至when 方法的成员Promise 对象附加回调来收集相应的结果。
var serverData = {}; var getting1 = $.get('/1') .done(function(result) {serverData['1'] = result;}); var getting2 = $.get('/2') .done(function(result) {serverData['2'] = result;}); $.when(getting1, getting2) .done(function() { // 获得的信息现在都已位于serverData…… });
函数的Promise用法
$.when 及其他能取用Promise 对象的jQuery 方法均支持传入非Promise 对象作为参数。这些非Promise 参数会被当成因相应参数位置已赋值而执行的Promise 对象来处理。例如$.when('foo')会生成一个因赋值'foo'而立即执行的Promise 对象。再譬如
var promise = $.Deferred().resolve('manchu'); $.when('foo', promise)会生成一个因赋值'foo'和'manchu'而立即执行的Promise 对象。代码:
var promise = $.Deferred().resolve(1, 2, 3); $.when('test', promise)会生成一个因赋值'test'和数组[1,2,3]而立即执行的Promise 对象。(请记住,Deferred 对象传递多个参数给resolve 方法时,$.when会把这些参数转换成一个数组。)
这带来了一个问题:$.when 如何知道参数是不是Promise 对象呢?
答案是:jQuery负责检查$.when 的各个参数是否带有promise 方法,如果有就使用该方法返回的值。Promise 对象的promise 方法会直接返回自身。
正如3.2.2 节所述,jQuery 对象也可以有promise 方法,这意味着$.when 方法强行将那些带promise 方法的jQuery 对象转换成了jQuery 动画版Promise 对象。因此,如果想生成一个在抓取某些数据且已完成#loading 动画之后执行的Promise 对象,只需写下下面这样的代码:
var fetching = $.get('/myData'); $.when(fetching, $('#loading'));只是请记住,必须要在动画开始之后再执行$.when 生成的那个Promise 对象。如果#loading 的动画队列为空,则立即执行相应的Promise 对象。