输出结果为:
start new Promise...
set timeout to: 1.7587399336588674 seconds.
call reject()...
Failed: timeout in 1.7587399336588674 seconds.
可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
job1.then(job2).then(job3).catch(handleError);其中,job1、job2和job3都是Promise对象。
下面的例子演示了如何串行执行一系列需要异步计算获得结果的任务:
start new Promise...
calculating 123 x 123...
calculating 15129 + 15129...
calculating 30258 x 30258...
calculating 915546564 + 915546564...
Got value: 1831093128
setTimeout可以看成一个模拟网络等异步执行的函数。现在,我们把上一节的AJAX异步执行函数转换为Promise对象,看看用Promise如何简化异步处理:
除了串行执行若干异步任务外,Promise还可以并行执行异步任务。
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1');});var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2');});// 同时执行p1和p2,并在它们都完成后执行then:Promise.all([p1, p2]).then(function (results) { console.log(results); // 获得一个Array: ['P1', 'P2']});
有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1');});var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2');});Promise.race([p1, p2]).then(function (result) { console.log(result); // 'P1'});
由于p1执行较快,Promise的then()将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃。
如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。
jQuery ajaxjQuery在全局对象jQuery(也就是$)绑定了ajax()函数,可以处理AJAX请求。ajax(url, settings)函数需要接收一个URL和一个可选的settings对象,常用的选项如下:
下面的例子发送一个GET请求,并返回一个JSON格式的数据:
var jqxhr = $.ajax('/api/categories', { dataType: 'json'});// 请求已经发送了不过,如何用回调函数处理返回的数据和出错时的响应呢?
function ajaxLog(s) { var txt = $('#test-response-text'); txt.val(txt.val() + '\n' + s);}$('#test-response-text').val('');var jqxhr = $.ajax('/api/categories', { dataType: 'json'}).done(function (data) { ajaxLog('成功, 收到的数据: ' + JSON.stringify(data));}).fail(function (xhr, status) { ajaxLog('失败: ' + xhr.status + ', 原因: ' + status);}).always(function () { ajaxLog('请求完成: 无论成功或失败都会调用');});get
对常用的AJAX操作,jQuery提供了一些辅助方法。由于GET请求最常见,所以jQuery提供了get()方法,可以这么写:
var jqxhr = $.get('/path/to/resource', {name: 'Bob Lee', check: 1
});
第二个参数如果是object,jQuery自动把它变成query string然后加到URL后面,实际的URL是:
/path/to/resource?name=Bob%20Lee&check=1这样我们就不用关心如何用URL编码并构造一个query string了。
postpost()和get()类似,但是传入的第二个参数默认被序列化为application/x-www-form-urlencoded:
var jqxhr = $.post('/path/to/resource', {name: 'Bob Lee',
check: 1
});
实际构造的数据name=Bob%20Lee&check=1作为POST的body被发送。
getJSON由于JSON用得越来越普遍,所以jQuery也提供了getJSON()方法来快速通过GET获取一个JSON对象:
var jqxhr = $.getJSON('/path/to/resource', { name: 'Bob Lee', check: 1}).done(function (data) { // data已经被解析为JSON对象了});安全限制
jQuery的AJAX完全封装的是JavaScript的AJAX操作,所以它的安全限制和前面讲的用JavaScript写AJAX完全一样。
如果需要使用JSONP,可以在ajax()中设置jsonp: 'callback',让jQuery实现JSONP跨域加载数据。