Promise 笔记
1. Promise 创建
Promise 对象是用于处理延时和异步调用场景,ES6中已经定稿,这个是未来的趋势
初始化对象
new Promise(function(resolve, reject) {
resolve('success');
}).then(function(arg){
console.log(arg);//success
}).then(function(arg){
console.log(arg);//success
});
对于Promise对象的链式处理方式
p.then(onFulfilled, onRejected);
p.then(function(value) {
}, function(reason) {
});
2. 异常处理
catch 和 Promise.prototype.then(undefined, onRejected) 是等同的,当需要注意的是其中catch和then的onRejected方法只能捕获一次异常
var p1 = new Promise(function(resolve, reject) {
resolve('Success');
});
p1.then(function(value) {
console.log(value); // "Success!"
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'); // 再次绑定捕获也不会再次被触发
});
// The following behaves the same as above
p1.then(function(value) {
console.log(value); // "Success!"
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'); //同样也不会被捕获
});
如果强制抛出了两次异常,例如:
var pro = new Promise(function(resolve, reject){
setTimeout(function(){
reject(new Error('this is error'));
},1000);
}).then(function(arg){
return Promise.reject('this is error 2');
}).catch(function(arg){
console.log(arg); // Error('this is error')
}).catch(function(arg){
console.log(arg); //undefined
});
这种场景下只有第一个异常会被捕获
3. Promise.all 监听多个promise的状态
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
var startDate = Date.now();
// 所有promise变为resolve后程序退出
Promise.all([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (values) {
console.log(Date.now() - startDate + 'ms'); // 約128ms
console.log(values); // [1,32,64,128]
});
必须等到所有的promise 的状态都变成FulFilled 之后才会触发all的成功方法
4. Promise.race 监听多个promise
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (value) {
console.log(value); // => 1
});
只要有任意的一个promise对象变成FulFilled状态,then中的方法就会被调用
再看看如果第一个promise执行完之后,其他的promise会不会继续执行
var winnerPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('this is winner');
resolve('this is winner');
}, 4);
});
var loserPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('this is loser');
resolve('this is loser');
}, 1000);
});
// 第一个promise变为resolve后程序停止
Promise.race([winnerPromise, loserPromise]).then(function (value) {
console.log(value); // => 'this is winner'
});
从结果来看其他的promise还是会继续执行的
5. 使用reject而不是throw
Promise的构造函数,以及被 then 调用执行的函数基本上都可以认为是在 try...catch 代码块中执行的,所以在这些代码中即使使用 throw ,程序本身也不会因为异常而终止。
如果在Promise中使用 throw 语句的话,会被 try...catch 住,最终promise对象也变为Rejected状态。
var promise = new Promise(function(resolve, reject){
throw new Error("message");
}).catch(function(error){
console.error(error);// => "message"
});
使用reject的优点
- 如果使用throw的话很难区分是我们主动抛出来的还是真正的其他异常,在Chrome中有 Pause On Caught Exceptions 不能区分
- 在 then 中使用reject的方法
var onRejected = console.error.bind(console);
var promise = Promise.resolve();
promise.then(function () {
return Promise.reject(new Error("this promise is rejected"));
}).catch(onRejected);
这样在 then 方法中可以很方便的控制流程,同时传递任意的参数
6. 最佳实践
实现一个超时调用
function delayPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
delayPromise(100).then(function () {
console.log("已经过了100ms!");
});
这样的超时调用更加的优雅