Promise 对象用于表示一个异步操作的最终完成 (或失败),及其结果值。
本质上,Promise 是一个被某些函数传出的对象,我们附加回调函数(callback)使用它,而不是将回调函数传入那些函数内部。
- Promise 状态
有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected。
var promise1 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'foo'); }); console.log(promise1); // expected output: [object 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
最后输出。
注意,调用resolve
或reject
并不会终结 Promise 的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
上面代码中,调用resolve(1)
以后,后面的console.log(2)
还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
上面代码中,setTimeout(fn, 0)
在下一轮“事件循环”开始时执行,Promise.resolve()
在本轮“事件循环”结束时执行,console.log('one')
则是立即执行,因此最先输出。
- 错误捕获
Promise 内部的错误不会影响到 Promise 外部的代码。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
推荐写法,使用 catch;catch 之后,再接 then,可以继续执行。
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
抛出错误可以用两种语法:
throw 'error message!';
或
return Promise.reject('error message!');
- Promise.all 将多个 Promise 实例,包装成一个新的 Promise 实例
接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例
Promise.all([p1, p2, p3])
如果作为参数的 Promise 实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。该实例执行完catch
方法后,也会变成resolved
,导致Promise.all()
方法参数里面的两个实例都会resolved
,因此会调用then
方法指定的回调函数。
Promise.all
等待所有都完成(或第一个失败)。
如果传入的 promise
中有一个失败(rejected),Promise.all
异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise
是否完成。
var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'one'); }); var p2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, 'two'); }); var p3 = new Promise((resolve, reject) => { reject('reject'); });
Promise.all([p1, p2, p3).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
//控制台打印:
//"reject"
//你也可以用 .catch
Promise.all([p1, p2, p3]).then(values => {
console.log(values);
}).catch(reason => {
console.log(reason)
});
//控制台打印:
//"reject"
- 加载图片
const preloadImage = function (path) {
return new Promise(function (resolve, reject) {
const image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = path;
});
};
- 传值方式
new Promise向下传值用 resolve,then 向下传值用 return。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise
.then(value => { return value + ' and bar'; })
.then(value => { return value + ' and bar again'; })
.then(value => { return value + ' and again'; })
.then(value => { console.log(value) })
.catch(err => { console.log(err) });