Promise出现原因
由于传统回调函数的方式写代码时,后一个异步请求发起依赖于当前请求的结果,。。。然后就产生了回调地狱,主要表现在代码的结构凌乱,不好写,不好阅读,不好维护,Promise的出现具有重大的意义,分析Promise的实现,可以更深层次的摸清函数的写法,参数的传递等JS规则
Promise常规使用
Promise请求有三种状态:pending(未决),resolved(已决),reject(已决),将Promise从未决推向已决后,不能再次改变状态
Promise同步代码结构:new一个Promise,promise里是一个已经内部绑定过的回调函数,该回调函数又由两个函数resolve和reject作为参数,通过resolve([参数])到达resolved状态,reject([参数])到达rejected状态。
Promise异步代码结构(thenable):即then那一部分,then里可注册resolved状态相关的回调函数,参数为resolve(x)中x的内容,比如resolve(19),该回调函数的参数就是19;then里可注册rejected状态相关的回调函数,参数为reject(x)中x的内容,比如reject(19),该回调函数的参数就是19
Promise异步代码结构(catchable):即catch那一部分,和thenable里的rejected状态部分差不多
new Promise((resolve,reject)=>{
setTimeout(function(){
// resolve(19)
reject(19)
},1000)
}).then(data=>{
console.log(data)
console.log("data")
},err=>{
console.log(err)
console.log("err1")
}).catch(err=>{
console.log(err)
console.log("err2")
})
//输出结果:
1. 如果是resolve(19), 19 data
2. 如果是reject(19), 19 err1
复制代码
上例中,因为在err1所处的回调中已经catch过了,在下一个catch位置前,其实是data为undefined的一个resolved(或fulfilled)的新Promise对象,因此catch不到错误信息了
Promise其他API
resolve
Promise.resolve(13)相当于new Promise(resolve=>{resolve(13)})
reject
Promise.reject(13)相当于new Promise(reject=>{reject(13)})
all
all中传递的是一个iterable类型,数组显然是。all应用场景为,等待所有的异步请球为resolved状态,all的thenable代码才运行;只要有一个rejected,就得去catch了
var t1 = function(){
return new Promise((resove,reject)=>{
setTimeout(function(){
resove(1)
},1000)
})
}
var t2 = function(){
return new Promise((resove,reject)=>{
setTimeout(function(){
resove(2)
},2000)
})
}
Promise.all([t1(),t2()]).then(data=>{
console.log(data)//两秒后两个异步请求为resolved,打印结果:(2) [1, 2]
//结果是和iterable类型中的请求一一对应的
})
复制代码
race
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
Promise async和await
async和await是语法糖,简化了Promise的写法,将请求的同步代码,和回应的一部代码更清晰的展现,增加可阅读性,可以不再使用then
async和await常规使用
async function test(){
await t1()
console.log("t1ok")//两秒时刻打印1
await t2()
console.log("t2ok")//三秒时刻打印2
}
复制代码
await等待异步响应,下面的代码不会执行,该进程交出控制权,等到异步响应到达,重新掌握控制器,执行后续同步代码,知道下一个await
await 1
注意await只能在async函数中使用,await的到的是Promise的状态数据
注意async函数中的return其实返回的一般是data值或rejected的err值
async function test2(){
await 1
//return await 1
}
test2().then(data=>{
console.log(data)//undefined
})
复制代码
console.log(await 1)发现为1,代码上加上return,相当于把状态数据传递给调用async函数所生成的新Promise,最终结果打印不再是undefined,而是1
async function test2(){
await 1
}
//官方给的等效代码
async function test2(){
return Promise.resolve(1).then(data=>undefined)
}
复制代码
async和await如何处理rejected响应
通过try…catch处理
function fn(){
return new Promise((resolve,reject)=>{
if(Math.random()<0.5){
resolve(1)
}else{
reject(2)
}
})
}
async function test3(){
try {
var res = await fn()
console.log(`resolved:${res}`)
} catch (error) {
console.log(`rejected:${error}`)
}
}
test3()
复制代码
多个Promise与reduce的组合
var fun1 = function(){console.log("fun1")}
var fun2 = function(){console.log("fun2")}
var fun3 = function(){console.log("fun3")}
var arrr = [fun1,fun2,fun3]
arrr.reduce((p,f)=>p.then(f),Promise.resolve())
/*打印结果:
fun1
fun2
fun3*/
复制代码
初始值Promise.resolve()将状态推向已决,这使得后续thenable队列中依次运行fun1,fun2,fun3
将setTimeout包装为Promise形式
setTimeout的异步是用旧的回调函数的,现在封装成Promise形式,可以结合await使用了
function delay(ms){
return new Promise((resolve,reject)=>{
setTimeout(resolve,ms)
})
}
async function test4(){
await delay(2000)
console.log("2秒到了")
}
test4()
复制代码
这个delay函数只有在异步中有效