Promise 对象可以理解为一次执行的异步操作,使用 promise 对象之后可以使用一种链式调用的方式来组织代码。比如使用 ajax 发一个A请求后,成功后拿到数据,我们需要把数据传给B请求,传统的写法会有多个嵌套一层层写下去,或者把第二个请求提取成另外一个方法,但这样增加了阅读成本,并不能一眼看出这两个请求是流程化两个连续请求;
HelloWorld
使用 Promise 构造方法创建对象
1 2 3 4 5
| var promise = new Promise(function(resolve,reject){ });
|
promise 对象实例有如下几个方法用于获取操作结果:
- then(callback) : 异步操作成功
- catch(callback) : 异步操作失败
- then(callback, errorCallback) : 上面两个方法分别只捕获成功/失败的情况,对于 then 的重载方法,可以传入两个 callback,第二个 callback 则用于处理失败的情况;
1 2 3 4 5 6 7 8
| var promise = new Promise(function(resolve){ console.log(1); resolve(3); }); promise.then(function(value){ console.log(value); }); console.log(2);
|
上面的代码执行后的输出结果是 1 2 3;
Promise 的三种状态
Promise 对象有三种状态:
- Resolve 可以理解为成功的状态;
- Rejected 可以理解为失败的状态;
- Pending 既不是 Resolve 也不是 Rejected 状态;该状态是Promise对象实例创建时候的初始状态;
Promise 对象中的resolve方法就是调用then对象的第一个函数,也就是成功的状态;而reject方法就是调用then对象的第二个函数,也就是失败的状态;
Call chaining
1 2 3 4 5 6 7 8 9 10 11 12
| var promise = new Promise(function(resolve){ resolve(3); }); promise.then(function(value){ console.log(value); return parseInt(value) + 1; }).then(function (value) { console.log(value); return parseInt(value) + 1; }).then(function (value) { console.log(value); })
|
上面的代码执行后输出结果是 3 4 5,因为每次 then() 调用后,都会返回一个 新的Promise对象,所以可以使用链式调用;如果传入 then() 的 callback 有返回值,则返回的 promise 对象的 then() 函数中 callback 将获取到该返回值;
then() 表示异步操作成功,会返回一个新的 promise 对象,但实际上 catch() 方法也会返回一个新的 promise 对象;
1 2 3 4 5 6 7 8 9 10 11
| var promise1 = new Promise(function(resolve){ resolve(3); }); var thenPromise = promise1.then(function(value){ console.log(value); }); var catchPromise = thenPromise.catch(function(error){ console.log(error); }); console.log(promise1 !== thenPromise); console.log(thenPromise !== catchPromise);
|
快速创建 Promise 对象
- Promise.resolve(value)
- Promise.reject(error)
Promise.all
假如有两个异步操作,不管他们的先后顺序,需要当这两个操作都成功后执行下一步操作,此时可以使用 Promise.all ;
1 2 3 4 5 6 7 8 9 10
| var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); Promise.all([p1, p2]).then(function (results) { console.log(results); });
|
Promise.race
Promise.race 是只要有一个 promise 对象 resolved 或者 rejected,程序就会停止,且会继续后面的处理逻辑;
1 2 3 4 5 6 7 8 9
| 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执行较快,Promise的then()将获得结果’P1’。
注:p2仍在继续执行,但执行结果将被丢弃!
JQuery ajax 中的 Promise
一个传统的 ajax 请求通常如下:
1 2 3 4 5 6
| $.ajax({ url: '', dataType:'json', success: function(data) { } });
|
我们可以使用 Promise 对该请求进行封装:
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
| function ajaxPromise(url, method="GET", data={}) { var promise = new Promise(function (resolve, reject) { $.ajax({ url: url, method: method, params: data, dataType: 'json', success: function (data) { resolve(data); }, error: function (err) { reject(err); } }) }); return promise; } ajaxPromise('https://api.github.com/emojis') .then(function (data) { return data.zzz; }) .then(function (zzz) { console.log(zzz); });
|
通过把 ajax 方法包装到 Promise 对象之中,使用 resolve() 和 reject() 把异步操作结果返回,这样就可以使用 then,catch 方法了。
JQuery 的 ajax 方法,实际上也返回了一个 Promise 对象。
1 2 3 4 5 6 7 8 9 10 11 12
| var jqPromise = $.ajax('/api/categories', { dataType: 'json' }); jqPromise.done(function (data) { ajaxLog('成功, 收到的数据: ' + JSON.stringify(data)); }).fail(function (xhr, status) { ajaxLog('失败: ' + xhr.status + ', 原因: ' + status); }).always(function () { ajaxLog('请求完成: 无论成功或失败都会调用'); });
|