这周我们结合JQ,对比前面学习过的Promise,进行分析。
Promise API
上周我们谈到了关于Promise的两个API,then以及catch。今天介绍resolve,reject,all。
1. Promise.resolve
一般情况下我们都会使用 new Promise() 来创建promise对象,但是除此之外我们也可以使用其他方法。在这里,我们将会学习如何使用 Promise.resolve 和 Promise.reject这两个方法。
静态方法Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。
比如 Promise.resolve(42); 可以认为是以下代码的语法糖。
1 2 3 4 5 6 7 8 9
| new Promise(function(resolve){ resolve(42); }); Promise.resolve(42).then(function(value){ console.log(value); });
|
强调一个 promise.resolve(thenable);接收的thenable对象具体指什么(类Promise对象:拥有名为.then方法的对象),我们举个例子。
到底什么样的对象能算是thenable的呢,最简单的例子就是 jQuery.ajax(),它的返回值就是thenable的。
因为jQuery.ajax() 的返回值是 jqXHR Object 对象,这个对象具有 .then 方法。
$.ajax('/json/comment.json');//拥有 .then方法的对象
这个thenable的对象可以使用 Promise.resolve 来转换为一个promise对象。
变成了promise对象的话,就能直接使用 then 或者 catch 等这些在 ES6 Promises里定义的方法了。
将thenable对象转换promise对象
1 2 3 4
| var promise = Promise.resolve($.ajax('/json/comment.json')); promise.then(function(value){ console.log(value); });
|
2. Promise.reject
Promise.reject(error)是和 Promise.resolve(value) 类似的静态方法,是 new Promise() 方法的快捷方式。
比如 Promise.reject(new Error(“出错了”)) 就是下面代码的语法糖形式。
1 2 3
| new Promise(function(resolve,reject){ reject(new Error("出错了")); });
|
这段代码的功能是调用该promise对象通过then指定的 onRejected 函数,并将错误(Error)对象传递给这个 onRejected 函数。
1 2 3
| Promise.reject(new Error("BOOM!")).catch(function(error){ console.error(error); });
|
3. Promise.all
Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法。
如下批量XHR的请求结果的例子,使用 Promise.all 的话代码会非常简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } var request = { comment: function getComment() { return getURL('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse); }, people: function getPeople() { return getURL('http://azu.github.io/promises-book/json/people.json').then(JSON.parse); } }; function main() { function recordValue(results, value) { results.push(value); return results; } var pushValue = recordValue.bind(null, []); return request.comment().then(pushValue).then(request.people).then(pushValue); } main().then(function (value) { console.log(value); }).catch(function(error){ console.error(error); });
|
之前例子中的 getURL 返回了一个promise对象,它封装了XHR通信的实现。 向 Promise.all 传递一个由封装了XHR通信的promise对象数组的话,则只有在全部的XHR通信完成之后(变为FulFilled或Rejected状态)之后,才会调用 .then 方法。
修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send(); }); } var request = { comment: function getComment() { return getURL('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse); }, people: function getPeople() { return getURL('http://azu.github.io/promises-book/json/people.json').then(JSON.parse); } }; function main() { return Promise.all([request.comment(), request.people()]); } main().then(function (value) { console.log(value); }).catch(function(error){ console.log(error); });
|
这个例子的执行方法和前面的例子一样。 不过Promise.all 在以下几点和之前的例子有所不同。
- main中的处理流程显得非常清晰。
- Promise.all 接收 promise对象组成的数组作为参数。Promise.all([request.comment(), request.people()]);
在上面的代码中,request.comment() 和 request.people() 会同时开始执行,而且每个promise的结果(resolve或reject时传递的参数值),和传递给 Promise.all 的promise数组的顺序是一致的。
也就是说,这时候 .then 得到的promise数组的执行结果的顺序是固定的,即 [comment, people]。
1 2 3
| main().then(function (results) { console.log(results); });
|
4. Promise.race
和 Promise.all 类似的对多个promise对象进行处理的 Promise.race 方法。
Promise.all 在接收到的所有的对象promise都变为 FulFilled 或者 Rejected 状态之后才会继续进行后面的处理, 与之相对的是 Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var winnerPromise = new Promise(function (resolve) { setTimeout(function () { console.log('this is winner'); resolve('this is winner'); }, 4); }); var loserPromise = new Promise(function (resolve) { setTimeout(function () { console.log('this is loser'); resolve('this is loser'); }, 1000); }); Promise.race([winnerPromise, loserPromise]).then(function (value) { console.log(value); });
|
上面例子我们还发现,Promise.race 在第一个promise对象变为Fulfilled之后,并不会取消其他promise对象的执行。