promise是一个对象,可以获取异步操作的消息。核心概念是“确保一件事情做完之后,再做另一件事情”。
(1)Pending:(进行中)
(2)Resolved:(已定型,等价于Fulfilled,已成功)
(3)Rejected:(已失败)
promise对象的特点:
1)对象的状态不受外界的影响。
只有异步操作的结果才能决定当前是哪一种状态,任何其他操作都无法改变这个状态。
“promise”的名字正是由这个特点而来,承诺,即表示其他手段无法改变;
2)一旦状态改变就不会再变,任何时候都可以得到这个结果。
promise对象状态的改变只有两种可能:
① Pending => Fulfilled(Resolved)
② Pending => Rejected
只要这两种情况发生,状态就凝固了,不会再变。
1)解决回调地狱的问题;
2)更好地进行错误捕获;
详细解析参见:http://www.hangge.com/blog/cache/detail_1635.html
1)无法取消promise,一旦创建它就会立即执行,无法中途取消;
2)如果不设置回调函数,promise内部抛出的错误不会反应到外部;
3)当处于Pending状态时,无法得知目前进展到哪一个阶段;
then方法就是把原来的回调函数写法分离出来,在异步操作执行完毕之后,用链式调用的方式执行回调函数;
(1)例子:定义做饭、吃饭、洗碗三个方法,它们是层层依赖的关系;
//做饭
function cook(){
console.log('开始做饭');
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('做饭完毕!');
resolve('蛋炒饭');
},1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:'+data);
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('吃饭完毕!');
resolve('待洗碗筷');
}, 2000);
});
return p;
}
//洗碗
function wash(data){
console.log('开始洗碗:'+data);
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('洗碗完毕!');
resolve('干净的碗筷');
}, 2000);
});
return p;
}
(2)使用then链式调用这三个方法
cook()
.then(function(data){
return eat(data);
})
.then(function(data){
return wash(data);
})
.then(function(data){
return console.log(data);
})
(3)简化写法如下:
cook()
.then(eat)
.then(wash)
.then(function(data){
return console.log(data);
});
运行结果如下:
上面样例我们通过 resolve 方法把 Promise 的状态置为完成态,这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。
而 reject 方法就是把 Promise 的状态置为已失败,这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。
1)举例如下:
//做饭
function cook(){
console.log('开始做饭');
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('做饭完毕!');
//失败
reject('烧焦的饭');
},1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:'+data);
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('吃饭完毕!');
//成功
resolve('待洗碗筷');
}, 2000);
});
return p;
}
cook()
.then(eat,function(data){
return console.log(data+'没法吃!');
});
运行结果如下:
2)如果只需要处理失败的情况,则把then中的第一个参数设置为null即可;
cook()
.then(null,function(data){
return console.log(data+'没法吃!');
});
1)它可以和 then 的第二个参数一样,用来指定 reject 的回调
cook()
.then(eat)
.catch(function(data){
return console.log(data+'没法吃!');
});
2)它的另一个作用是,当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中。
//做饭
function cook(){
console.log('开始做饭');
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('做饭完毕!');
//失败
resolve('蛋炒饭');
},1000);
});
return p;
}
//吃饭
function eat(data){
console.log('开始吃饭:'+data);
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('吃饭完毕!');
//成功
resolve('待洗碗筷');
}, 2000);
});
return p;
}
cook()
.then(function(data){
throw new Error('饭打翻了');
eat(data);
})
.catch(function(data){
return console.log(data);
});
运行结果:
这种错误的捕获是非常有用的,因为它能够帮助我们在开发中识别代码错误。比如,在一个 then() 方法内部的任意地方,我们做了一个 JSON.parse() 操作,如果 JSON 参数不合法那么它就会抛出一个同步错误。用回调的话该错误就会被吞噬掉,但是用 promises 我们可以轻松的在 catch() 方法里处理掉该错误。
3)还可以添加多个 catch,实现更加精准的异常捕获。
somePromise.then(function() {
return a();
}).catch(TypeError, function(e) {
//If a is defined, will end up here because
//it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
//Will end up here if a wasn't defined at all
}).catch(function(e) {
//Generic catch-the rest, error wasn't TypeError nor
//ReferenceError
});
promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完毕才执行回调。
1)比如下面代码,两个异步操作是并行的,等到它们都执行完成后才会进到then里面。同时all会把所有异步操作的结果放进一个数组中传给then。
//切菜
function cut(){
console.log('开始切菜');
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('切菜完毕!');
//成功
resolve('切好的菜');
},1000);
});
return p;
}
//烧水
function boil(){
console.log('烧水切菜');
var p=new Promise(function(resolve,reject){
setTimeout(function(){
console.log('烧水完毕!');
//成功
resolve('烧好的水');
},1000);
});
return p;
}
Promise
.all([cut(),boil()])
.then(function(results){
console.log('准备工作完毕');
console.log(results);
})
运行结果如下:
race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。
注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。
1)这里我们将上面样例的 all 改成 race
Promise
.race([cut(),boil()])
.then(function(results){
console.log('准备工作完毕');
console.log(results);
})
运行结果如下:
2)race 使用场景很多。比如我们可以用 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 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。
原文出自:www.hangge.com 转载:http://www.hangge.com/blog/cache/detail_1638.html