目录
1.概念
-
javascript是单线程执行方式,为了避免耗时的任务形成阻塞,需要使用异步编程方案来解决。
-
回调函数,是js中异步编程方式的根基
2.Promise异步编程方案
使用回调函数来定义异步任务结束后的操作
const promise = new Promise(function(resolve, reject){
resolve(100)
reject(new Error('promise reject'))
})
promise.then(function(res){
console.log('success', res)
}, function(err){
console.log(err)
})
2.1 常见使用误区
回调地狱(多层回调嵌套使用)
function getData(dataUrl){
return new Promise(function(resolve, reject){
if(success){
resolve(res)
}else{
reject(err)
}
})
}
// 顺序打印res1,res2,res3...
getData(url1).then(function(res1){
console.log(res1)
getData(url2).then(function(){
console.log(res2)
getData(url3).then(function(){
...
})
})
})
2.2 链式调用
Promise 的 then 方法返回一个新的Promise实例,因此可以继续调用 then 方法,为这个新的Promise对象指定回调函数
getData(url1)
.then(function(res1){
console.log(res1)
return getData(url2)
})
.then(function(res2){
// 如果上一个then中回调函数的返回值是一个Promise,下一个then将为这个Promise指定回调
console.log(res2)
return getData(url3)
})
.then(function(res3){
console.log(res3)
return 'str'
})
.then(function(res4){
// 上一个then中的回调函数的返回值(一个字符串),会作为下一个then中回调函数的参数
console.log(res4) //'str'
})
.then(function(res5){
// 如果上一个then中的回调函数没有返回值,默认返回undefined
congsole.log(res5) //undefined
})
2.3 异常处理
- 链式调用中更推荐在catch方法中定义失败回调。
- catch方法本质与then相同,相当于第一个参数也就是成功回调传的是undefined
- catch是为上一个then返回的新的promise添加回调。如果then中的回调 返回值是一个promise,并且这个promise执行中出现了异常,在当前这个then中定义失败回调是捕获不到的,而链条上的异常是一直向后传递的,所以catch一定能捕获到。
2.4 静态方法
- Promise.resolve()
- Promise.reject()
- Promise.all()
- all方法的参数是一个promise对象数组,
- 返回值是一个全新的promise对象,
- 这个promise对象的成功回调的参数是每个promise执行的结果数组,
- 只有所有promise都成功,新的promise才会是成功状态,只要有一个失败了,新的promise就以失败结束。
let promise = Promise.all([
getData(url1),
getData(url2),
getData(url3)
])
promise.then(function(res){
congsole.log(res)
//[data1, data2, data3]
}).catch(function(err){
congsole.log(err)
})
- Promise.race()
race方法的参数也是一个promise数组,与all方法不同的是,它不是等待所有异步任务完成,而是以第一个结束的任务为准。
3.Generator异步编程方案
生成器函数Generator,定义时在普通函数基础上加一个 * 号
function * fn(){
consolo.log('start')
let x = yield 123
console.log(x) //undefined
let y = yield 456
console.log(y) //2468
return 789
}
const generator = fn()
generator.next() //{value:123, done:false}
generator.next() //{value:456, done:false}
generator.next(2468) //{value:789, done:true}
- 生成器函数调用后不会立即执行,而是返回一个生成器对象,调用该对象的next方法,函数才会开始执行
- 当执行中遇到yield命令,暂停执行,并将yield后边的表达式的值作为返回的对象的value
- next方法可以带一个参数,作为上一个yield表达式的返回值,否则yield表达式本身返回undefined
3.1 Generator 结合 Promise 的异步方案
function * main(){
const data1 = yield getData(url1)
congsole.log(data1)
const data2 = yield getData(url2)
congsole.log(data2)
const data3 = yield getData(url3)
congsole.log(data3)
}
const g = main()
const result = g.next() //返回promise1
if(result.done) return
result.value.then(data => {
const result2 = g.next(data) //返回promise2,给data1赋值
if(result2.done) return
result2.value.then(data => {
conse result3 = g.next(data) //返回pronise3,给data2赋值
if(result3.done) return
result3.value.then(data => {
g.next(data) //返回undefined,done为true,给data3赋值
})
})
})
//使用递归方式执行Generator函数
function handleResult(result){
if(result.done) return
result.value.then(data => {
handleResult(g.next(data))
})
}
// const g = main()
// handleResult(g.next)
3.2 async / await 语法糖
- async内置执行器,不需要调用next方法就能自动往下执行
- async函数返回一个Promise对象,可以直接使用then方法指定回调
async function main(){
const data1 = await getData(url1)
congsole.log(data1)
const data2 = await getData(url2)
congsole.log(data2)
const data3 = await getData(url3)
congsole.log(data3)
}
const result = main()
result.then(() => {
...
})