1. 简介
ES6引入了一个全新的对象Promise,用于表示一个异步操做的最终状态(完成或失败),以及其返回的值。Promise最直接的好处就是链式调用,另外在错误捕获上也很方便。用同步的写法解决异步问题,代码直观,易于理解维护,解决了回调地狱的问题。关于Promise的详细讲解和更多用例我会开专门文章讨论。这里咱们主要看一下Promise及其原型的属性和方法。php
2. Promise对象建立
Promise对象使用new构造函数建立。基本使用方法以下:es6
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操做成功 */){ resolve(value); } else { reject(error); } });
Promise构造函数接受一个函数做为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用本身部署。json
then方法能够接受两个回调函数做为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不必定要提供。这两个函数都接受Promise对象传出的值做为参数。数组
var promise = new Promise(function(resolve, reject) { setTimeout(resolve, 1000, 'foo'); }); promise.then(function(val){ console.log(val); // 1000ms后输出 ‘foo’ })
3. Promise构造函数的属性与方法
咱们用Object.getOwnPropertyNames()方法获取Promise构造函数的全部属性与方法。promise
Object.getOwnPropertyNames(Promise); // (7) ["length", "name", "prototype", "all", "race", "resolve", "reject"]
发现一共有7个属性和方法。ruby
3.1 Promise构造函数的属性
Promise.length
长度总为1 (构造器参数的数目)app
Promise.name
名称为"Promise"异步
Promise.prototype
指向Promise构造函数的原型,能够为全部 Promise 类型的对象添加属性。svg
3.2 Promise构造函数的方法
Promise.all(iterable)
这个方法返回一个新的promise对象,该promise对象在iterable参数对象里全部的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则当即触发该promise对象的失败。这个新的promise对象在触发成功状态之后,会把一个包含iterable里全部promise返回值的数组做为成功回调的返回值,顺序跟iterable的顺序保持一致;若是这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息做为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(能够参考jQuery.when方法---MDN Promise译者注)函数
var promise1 = Promise.resolve(3); var promise2 = 42; var promise3 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]).then(function(values) { console.log(values); }); // expected output: Array [3, 42, "foo"]
固然,当参数不包含 Promise 时, 该方法返回完成(resolve),但这显然没有什么意义。
Promise.race(iterable)
当iterable参数里的任意一个子promise被成功或失败后,父promise立刻也会用子promise的成功返回值或失败详情做为参数调用父promise绑定的相应句柄,并返回该promise对象。
var promise1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); }); var promise2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'two'); }); Promise.race([promise1, promise2]).then(function(value) { console.log(value); // Both resolve, but promise2 is faster }); // expected output: "two"
Promise.reject(reason)
返回一个状态为失败的Promise对象,并将给定的失败信息reason(Promise被拒绝的缘由)传递给对应的处理方法。此处使用Error实例的reason对调试和选择性错误捕捉颇有帮助。
Promise.reject("Testing static reject").then(function(reason) { // 未被调用 }, function(reason) { console.log(reason); // "Testing static reject" }); Promise.reject(new Error("fail")).then(function(error) { // 未被调用 }, function(error) { console.log(error); // 堆栈跟踪 /* Error: fail at <anonymous>:7:16 */ });
Promise.resolve(value)
返回一个状态由给定value决定的Promise对象。若是该值是一个Promise对象,则直接返回该对象;若是该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;不然的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,而且将该value传递给对应的then方法。一般而言,若是你不知道一个值是不是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。
用法以下:
Promise.resolve(promise);
直接返回该对象promisePromise.resolve(thenable);
返回一个最终状态由then方法执行决定的Promise对象Promise.resolve(value)
value为空,基本类型,或者不带then方法的对象,返回状态为fulfilled的Promise对象,而且将该value传递给对应的then方法
基本用法示例:
var promise1 = Promise.resolve([1, 2, 3]); promise1.then(function(value) { console.log(value); // expected output: Array [1, 2, 3] });
4. Promise原型对象的属性与方法
咱们用Object.getOwnPropertyNames()方法获取Promise原型对象的全部属性与方法。
Object.getOwnPropertyNames(Promise.prototype); // (4) ["constructor", "then", "catch", "finally"]
发现一共有4个属性和方法。
4.1 Promise原型对象的属性
Promiset.prototype.constructor
指向构造函数Promise
4.2 Promise原型对象的方法
Promise.prototype.then(onFullfilled, onRejected)
它最多须要有两个参数:Promise 的接受(fulfillment)和拒绝(rejection)状况的回调函数。返回一个新的 Promise,该Promise将以回调的返回值来resolve。
语法:
p.then(onFulfilled, onRejected); p.then(function(value) { // fulfillment }, function(reason) { // rejection });
参数:
- onFulfilled
当Promise变成接受状态(fulfillment)时,该参数做为回调函数被调用。该函数有一个参数,即接受的值(the fulfillment value)。 - onRejected
当Promise变成拒绝状态(rejection )时,该参数做为回调函数被调用。该函数有一个参数,即拒绝的缘由(the rejection reason)。
返回值:
then方法返回一个Promise。而它的行为与then中的回调函数的返回值有关:
若是then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,而且将返回的值做为接受状态的回调函数的参数值。
若是then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,而且将抛出的错误做为拒绝状态的回调函数的参数值。
若是then中的回调函数返回一个已是接受状态的Promise,那么then返回的Promise也会成为接受状态,而且将那个Promise的接受状态的回调函数的参数值做为该被返回的Promise的接受状态回调函数的参数值。
若是then中的回调函数返回一个已是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,而且将那个Promise的拒绝状态的回调函数的参数值做为该被返回的Promise的拒绝状态回调函数的参数值。
若是then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,而且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
注意:
若是忽略针对某个状态的回调函数参数,或者提供非函数 (nonfunction) 参数,那么 then 方法将会丢失关于该状态的回调函数信息,可是并不会产生错误。若是调用 then 的 Promise 的状态(fulfillment 或 rejection)发生改变,可是 then 中并无关于这种状态的回调函数,那么 then 将建立一个没有通过回调函数处理的新 Promise 对象,这个新 Promise 只是简单地接受调用这个 then 的原 Promise 的终态做为它的终态。
用法示例:
var promise1 = new Promise(function(resolve, reject) { resolve('Success!'); }); promise1.then(function(value) { console.log(value); // expected output: "Success!" });
Promise.catch(onRejected)
添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。
语法:
p.catch(onRejected); p.catch(function(reason) { // 拒绝 });
参数:
- onRejected
当Promise 被拒绝时,被调用的一个Function。该函数拥有一个参数: - reason
拒绝的缘由。
返回值:
一个Promise。
示例:
有三种常见的使用状况:
- 使用链式语句的 catch方法:
var p1 = new Promise(function(resolve, reject) { resolve('Success'); }); p1.then(function(value) { console.log(value); // "成功!" throw 'oh, no!'; }).catch(function(e) { console.log(e); // "oh, no!" }).then(function(){ console.log('after a catch the chain is restored'); }, function () { console.log('Not fired due to the catch'); }); // 如下行为与上述相同 p1.then(function(value) { console.log(value); // "成功!" return Promise.reject('oh, no!'); }).catch(function(e) { console.log(e); // "oh, no!" }).then(function(){ console.log('after a catch the chain is restored'); }, function () { console.log('Not fired due to the catch'); });
- 捕获抛出的错误
// 抛出一个错误,大多数时候将调用catch方法 var p1 = new Promise(function(resolve, reject) { throw 'Uh-oh!'; }); p1.catch(function(e) { console.log(e); // "Uh-oh!" }); // 在异步函数中抛出的错误不会被catch捕获到 var p2 = new Promise(function(resolve, reject) { setTimeout(function() { throw 'Uncaught Exception!'; }, 1000); }); p2.catch(function(e) { console.log(e); // 不会执行 }); // 在resolve()后面抛出的错误会被忽略 var p3 = new Promise(function(resolve, reject) { resolve(); throw 'Silenced Exception!'; }); p3.catch(function(e) { console.log(e); // 不会执行 });
- 若是已决议
//建立一个新的 Promise ,且已决议 var p1 = Promise.resolve("calling next"); var p2 = p1.catch(function (reason) { //这个方法永远不会调用 console.log("catch p1!"); console.log(reason); }); p2.then(function (value) { console.log("next promise's onFulfilled"); /* next promise's onFulfilled */ console.log(value); /* calling next */ }, function (reason) { console.log("next promise's onRejected"); console.log(reason); });
Promise.prototype.finally(onFinally)
添加一个事件处理回调于当前promise对象,而且在原promise对象解析完毕后,返回一个新的promise对象。回调会在当前promise运行完毕后被调用,不管当前promise的状态是完成(fulfilled)仍是失败(rejected)
注意:
finally() 虽然与 .then(onFinally, onFinally) 相似,它们不一样的是:
- 调用内联函数时,不须要屡次声明该函数或为该函数建立一个变量保存它。
因为没法知道promise的最终状态,因此finally的回调函数中不接收任何参数,它仅用于不管最终结果如何都要执行的状况。 - 与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不一样,Promise.resolve(2).finally(() => {}) resolved的结果为 2。
- 一样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3。
用法示例:
一个典型的用法,在发出请求时,页面的loading效果开启,而后无论返回的结果是完成(fulfilled)仍是失败(rejected),都会执行onFinally将loading效果取消。
let isLoading = true; fetch(myRequest).then(function(response) { var contentType = response.headers.get("content-type"); if(contentType && contentType.includes("application/json")) { return response.json(); } throw new TypeError("Oops, we haven't got JSON!"); }) .then(function(json) { /* process your JSON further */ }) .catch(function(error) { console.log(error); }) .finally(function() { isLoading = false; });
- Promise实例对象的属性与方法
咱们用Object.getOwnPropertyNames()方法获取Promise实例对象的全部属性与方法。
var p = new Promise(function(resolve, reject) { resolve('success'); }) Object.getOwnPropertyNames(p); // []
咱们发现实例自己没有绑定属性与方法。
参考
本文同步分享在 博客“love丁酥酥”(JianShu)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。