一.介绍
是一个容器,里面保存着某个未来才会结束的事件的结果,通常是异步操作。
promise对象有两个特点:
- 对象状态不受外界影响
- 一旦状态改变,便不会再变
对象的状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
promise是一个构建函数,用来生成promise实例。
const promise = new Promise(function(resolve, reject) {// ... some codeif (/* 异步操作成功 */){resolve(value);} else {reject(error);}});promise.then(function(value) {// success}, function(error) {// failure});
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
let promise = new Promise(function(resolve, reject) {console.log('Promise');resolve();});promise.then(function() {console.log('resolved.');});console.log('Hi!');// Promise// Hi!// resolved
上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完后才会执行,所以resolved最后输出。
实例:
const getJSON = function(url) {const promise = new Promise(function(resolve, reject){const handler = function() {if (this.readyState !== 4) {return;}if (this.status === 200) {resolve(this.response);} else {reject(new Error(this.statusText));}};const client = new XMLHttpRequest();client.open("GET", url);client.onreadystatechange = handler;client.responseType = "json";client.setRequestHeader("Accept", "application/json");client.send();});return promise;};getJSON("/posts.json").then(function(json) {console.log('Contents: ' + json);}, function(error) {console.error('出错了', error);});
new完promise,并没有调用它,我们传进去的函数就已经执行了,这是需要注意的一个细节。所以我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数,如:
function runAsync(){var p = new Promise(function(resolve, reject){//做一些异步操作setTimeout(function(){console.log('执行完成');resolve('随便什么数据');}, 2000);});return p;}runAsync()
二.then()方法
Promise 实例具有then方法,作用是为 Promise 实例添加状态改变时的回调函数,then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。
三.catch()方法
catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
promise.then(function(data) { //cb// success}).catch(function(err) {// error});
四.finally()
不管 Promise 对象最后状态如何,都会执行的操作.
promise.then(result => {···}).catch(error => {···}).finally(() => {···});
五.Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例.
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
// 生成一个Promise对象的数组const promises = [2, 3, 5, 7, 11, 13].map(function (id) {return getJSON('/post/' + id + ".json");});Promise.all(promises).then(function (posts) {// ...}).catch(function(reason){// ...});
六.Promise.resolve()
有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用。
Promise.resolve('foo')// 等价于new Promise(resolve => resolve('foo'))
七.Promise.race()
比谁跑得快
//请求某个图片资源function requestImg(){var p = new Promise(function(resolve, reject){var img = new Image();img.onload = function(){resolve(img);}img.src = 'xxxxxx';});return p;}//延时函数,用于给请求计时function timeout(){var p = new Promise(function(resolve, reject){setTimeout(function(){reject('图片请求超时');}, 5000);});return p;}Promise.race([requestImg(), timeout()]).then(function(results){console.log(results);}).catch(function(reason){console.log(reason);});
requestImg函数会异步请求一张图片,我把地址写为”xxxxxx”,所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息
八.应用
const preloadImage = function (path) {return new Promise(function (resolve, reject) {const image = new Image();image.onload = resolve;image.onerror = reject;image.src = path;});};
