特点:
1. 对象的状态不收外界影响,代表一个异步操作,存在三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态
2. 一旦状态发生改变,就不再再变。
3. Promise 无法取消,一旦新建就会立即执行,无法中途取消。如果不设置回调函数,Promise内部抛出的错误,就无法反应到外部(所以设置一个promise关联另一个promise时,并不是那顺序执行,而是同时执行,只不过状态产生了相互依赖性)
4. 处于 pending 状态时,无法得知目前进展到了哪一个阶段(是刚开始还是即将完成)
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。他们是两个函数
resolve:异步操作成功时调用,并将异步操作的结果作为参数传递出去
rejected:异步操作失败时,将报出的错误作为参数传递出去
Promise实例生成后,可以使用 then 方法分别指定 resolved 和 rejected 状态的回调函数。then 方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行
注意:在写法上,一般调用了 resolve 或者 reject 后,Promise 的使命就完成了,后续操作应该放在 then 方法里面,所以这里最后加上 return 语句
// 理解这段代码的执行顺序
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => {
return reject(new Error('fail'))
}, 500)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => {
return resolve(p1)
}, 1000)
})
p2.then(result => {
console.log('result: ', result)
}).catch(error => {
console.log('error of p2: ', error)
})
then 方法是定义在原型对象上的,他返回的是一个新的 Promise 实例,可以采用链式写法,即 then 后面再调用另一个 then 方法
这个方法是 .then(null, rejection) 的别名,用于指定发生错误时的回调函数
注意:Promise 在 resolve 语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变。且 Promise 对象的错误具有冒泡性质,会一直往后进行传递,直到捕获为止
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
在写法上,不要在 then 方法里面定义 reject 状态的回调函数,总是使用 catch 方法(因为这样可以捕获前面的方法中执行的错误)。还有就是建议在 Promise 对象的后面有跟 catch 方法,这样可以处理 Promise 内部发生的错误。而且因为 catch 方法返回的还是一个 Promise 对象,因此后面还可以接着调用 then 方法
Promise 内部的错误不会影响到 Promise 外部代码的执行
// 这里 promise 已经执行结束,最终冒泡到最外层成了未捕获的错误
const promise = new Promise(function (resolve, reject) {
resolve('ok');
setTimeout(function () { throw new Error('test') }, 0)
});
promise.then(function (value) { console.log(value) });
// ok
// Uncaught Error: test
// Promise 后直接跟一个 catch 方法,方便捕获错误
Promise.resolve()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// carry on
这个方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。而且这个方法的回调函数不接受任何参数,这意味着没有办法知道前面的的状态到底是 resolve 还是 reject。所以这个方法与状态无关,不依赖于 Promise 的执行结果。finally 方法总是会返回原来的值
// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.reject(3).finally(() => {})
// 实现方式
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
该方法用于将多个 Promise 实例,包装成一个新的 Promise 实例(该方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例)
const p = Promise.all([p1, p2, p3])
这里 p 的状态由 p1、p2、p3 决定
1. 三者都变为 fulfilled,p 的状态才会变成 fulfilled,此时三者的返回值组成一个数组,传递给 p 的回调函数
2. 只要三者中有一个被 rejected,那 p 的状态就变成 rejected,此时第一个被 reject 的实例返回值,会传递给 p 的回调函数
const promises = [1, 2, 3, 4, 5].map(id => {
return getJSON('/post/' + id + '.json')
})
Promise.all(promises).then(post => {
// ...
}).catch(reason => {
// ...
})
注意:如果作为参数的 Promise 实例,自己定义了 catch 方法,那么他一旦被 rejected,并不会触发 Promise.all() 的catch 方法,如果没有自己的 catch 方法,就会调用 Promise.all() 的 catch 方法
// 理解这段代码
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
该方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,只有数组参数其中有一个率先改变了状态,就会将这个最新改变的 Promise 对象实例的返回值,就传递给这个 p 的回调函数、
const p = Promise.race([p1, p2, p3])
可以将参数对象转为 Promise 对象
const jsPromise = Promise.resolve($.ajax('/getJson.json'))
这个方法其实等价于
Promise.resolve('foo')
new Promise(resolve => resolve('foo'))
该方法的参数分为四种情况:
1. 参数是一个 Promise 实例(此时该方法不做任何修改,原封不动的将这个实例进行返回)
2. 参数是一个 thenable 对象,即具有 then 方法的对象(会将这个对象转为 Promise 对象,然后立即执行 thenable 对象的 then 方法)
3. 参数不是具有 then 方法的对象,或根本就不是对象(返回一个新的 Promise 对象,状态为 resolved)
4. 不带有任何参数(直接返回一个 resolved 状态的 Promise 对象,这里返回的对象,是在本轮 event loop 的结束时,而不是下一轮的开始时)
返回一个新的 Promise 实例,该实例的状态为 rejected。需要注意的是 Promise.reject() 方法的参数,会原封不动的作为 reject 的理由,变成后续方法的参数,并不会像 Promise.resolve() 那样对参数进行转换
可以获取同步和异步的错误,就像是在模拟 try 代码块