Promise对象是做什么的?
答:操作异步使用的方法。
本章博客简单介绍一下 promise 的用法,耐心看完其实并不难。
学过 javascript 的同学都应该清楚,js在进程是单线程的,也就是代码在同步进行解析。有些时候,异步操作是有必要的,在没有promise之前,我们一般使用回调函数,加一个延时执行来实现这一功能,例如:
function foo(){
setTimeout(()=>{
// 异步代码
},1000)
}
回调函数这种方法不好的一点:如果做多个异步操作时,会产生回调地狱,会使代码看起来特别的混乱。如:
// 每隔2秒执行一次异步操作
function foo(i){
setTimeout(()=>{
i();
},2000);
}
foo(function(){
console.log("异步操作1");
foo(function(){
console.log("异步操作2");
foo(function(){
console.log("异步操作3");
foo(function(){
console.log("异步操作4");
foo(function(){
console.log("异步操作5");
});
});
});
});
});
// 这是个神奇的回调地狱,源源不断,层层嵌套
在ES6以后,出现了Promise对象,这个在实现异步操作,会解决回调地狱的问题。
Promise规范:
构造Promise首字母需大写:
var pro = new Promise() // 首字母大写
promise 有三种状态,并且一旦发出请求后,就不能终止,并且状态不可逆,也不能再次发生改变!(下面这三种状态要记下来,面试会问)。
pending (等待)
fulfilled (完成)
rejected (未完成)
两种线程,
一个是从pending(等待)到fulfilled(完成);
一个是从pending(等待)到rejected(未完成);
这两种状态分别走两个方法,一个是
then // 成功走then
另一个是
catch // 失败走catch
所以我们在使用Promise时,可以通过这两个方法,来实现成功后的操作,和失败后的操作。
那么我们如何让状态发生改变呢?在Promise对象中,提供了两个方法resolve()
和 reject()
resolve() : pending状态 -> fulfilled状态 // resolve() 使 “等待” 状态改变成 “完成” 状态
reject() : pending状态 -> rejected状态 // reject() 使 “等待” 状态改变成 “未完成” 状态
先不要懵,以上这些概念性问题先看懂,我们可以举例了:
function foo(){
var pro = new Promise(function(resolve,reject){
resolve(); // resolve()方法,让状态变成完成状态,所以走then,不走catch
});
return pro; // ️注意:需要抛回Promise对象,否则会报错。
}
foo().then(function(){
console.log('成功');
}).catch(function(){
console.log('失败');
});
// 打印出来后,结果为“成功”
// 因为上边有个resolve()方法,所以把状态改为了成功的状态,所以走then后的代码。
// 如果把resolve()方法改成reject(),结果就变成了“失败”。
上边的案例很基础,所以你们肯定会看懂。
除了这个单一的异步操作外,Promise还可以连续的做若干个异步,完美的解决回调地狱的问题。如:
function foo(){
var pro = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve();
},2000)
})
return pro;
}
foo()
.then(()=>{
console.log('异步操作1')
return foo();
})
.then(()=>{
console.log('异步操作2')
return foo();
})
.then(()=>{
console.log('异步操作3')
return foo();
})
.then(()=>{
console.log('异步操作4')
return foo();
})
.then(()=>{
console.log('异步操作5')
return foo();
})
// 输出结果,每隔2秒中,打印一次。
// 想写几个异步操作就写几个,解决了回调地狱的问题。
除此之外,Promise还可以并行执行异步任务,有两个方法 all()
和 race()
all() 多个异步操作全部完成,才执行 then() ;有一个没完成返回失败
race() 多个异步操作,谁先触发状态,返回谁的结果,再有触发的也不会返回结果了。
使用也是很简单,方法中使用数组的方式使用:
Promise.all( [ A(), B(), C(), D() ] ).then()
Promise.race( [ A(), B(), C(), D() ] ).then()
举个all()
的例子:
试想王者荣耀这个游戏,多名玩家的游戏全部加载到100%,才开始进入游戏开局页面。
function zhenJi(){
var zj = new Promise(function(resolve,reject){
setTimeout(()=>{
console.log("甄姬加载中……")
resolve()
},2000)
})
return zj
}
function yaSe(){
var ys = new Promise(function(resolve,reject){
setTimeout(()=>{
console.log("亚瑟加载中……")
resolve()
},3000)
})
return ys
}
Promise.all([zhenJi(),yaSe()]).then(()=>{
console.log('游戏开始')
})
// 2s之后先输出“甄姬加载中……”,3s后同时输出 “亚瑟加载中……” “游戏开始”
race()
方法同理,只是哪个先执行完,就返回哪一个。
var a1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, '甄姬');
});
var a2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, '、亚瑟');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // '甄姬'
});
注意一些问题:
几个方法不要忘记,几种状态记在心里。
成功方法走then,失败方法走catch。
promise立即执行,但不要忘记是异步执行。