ES7——async和await

来看一个async/await和Promise.then的使用对比
在这里插入图片描述
await紧跟一个Promise实例,返回一个resolve或reject的结果,属于同步任务
await后面行的内容相当于Promise.then()内执行的内容,就是异步任务

async

async声明的函数的返回本质上是一个Promise,所以要获得async声明的函数的返回值需要用then方法返回

async function test(){
	return Promise.resolve("async")
	// return "async"也可,因为会自动解析成Promise.resolve('async')
}
// test() 如果直接调用则返回Promise {<resolved>: "async"}对象
test().then(function(result){
	console.log(result)
})

输出async

await

await是在等待一个Promise的异步返回,后面才能继续执行
一个延时输出的例子

async function test(ms){
    console.log("hello")
    await new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve()
        },ms)
    })
    console.log("world")
}
test(1000)

输出hello,1s后输出world

但是如果await跟的返回值不是Promise

async function test(ms){
    console.log("hello")
    await setTimeout(()=>{
            console.log("延时")
        },ms)

    console.log("world")
}
test(1000)

输出hello world 延时,await没有起到异步的作用,setTimeout作为宏任务被放到最后执行。
也就是说一般await会跟Promise实例搭配实现异步,用来代替then

链式调用中的Promise和async await

设置间隔一段时间之后输出内容,sleep函数用于设置间隔时间,返回一个Promise函数

// 写一个函数返回Promise对象,
var sleep = function(ms){
    return new Promise(function(resolve,reject){
        // 判断输入类型,reject给后面的函数catch传入参数
        if(typeof ms != "number"){reject(new Error("输入错误"))}    

        // 用计时器设置延时输出,resolve给后面的函数then传入参数
        setTimeout(function(){
            resolve("延迟了 " + ms + " 毫秒输出")
        },ms)
    })
}

用then的写法。then式链式写法的本质其实是一直往下传递返回一个新的Promise,也就是说then在下一步接收的是上一步返回的Promise

sleep(1000).then(function(result){
    console.log(result)
    return sleep(2000)      // 链式调用的关键,上一层结束后返回一个Promise对象
}).then(function(result){   // 在下一层then执行上面Promise的resolve
    console.log(result)
    return sleep(5000)
}).then(function(result){
    console.log(result)
}).catch(function(error){   // 捕获错误
    console.log(error)
}).finally(function(){      // 无论是否catch到错误都会执行finally
    console.log("这是一个延时输出函数")
})

用await的写法。await紧跟一个Promise对象,返回resolve或reject结果

(async ()=>{
	try{
		console.log(await sleep(1000))
		console.log(await sleep(2000))
		console.log(await sleep(3000))
	}
	catch(e){
		console.log(e)
	}
})()

用for循环+async/await实现链式调用

async function test(){
    arr = [sleep(1000),sleep(2000),sleep(5000)]
    for(var i = 0; i < arr.length; i++){
        console.log(await arr[i])
    }
}
test()

解决回调陷阱常用方法:
function拆解
事件发布/订阅模式
Promise
Generator
async / await

链式写法的错误处理

见上面用then的写法,只要在最后写一个catch即可,因为链式写法的错误处理具有“冒泡”特性,链式中任何一个环节出问题,都会被catch到,同时在某个环节后面的代码就不会执行了

注意catch只是捕获错误的一个链式表达,并不是break!所以,catch放的位置也很有讲究,一般放在一些重要的、必须catch的程序的最后。这些重要的程序中间一旦出现错误,会马上跳过其他后续程序的操作直接执行到最近的catch代码块,但如果catch后面还有then还是会执行

return await

async function waitAndMaybeReject(){
    // 等待1秒钟
    await new Promise(resolve => setTimeout(resolve, 1000));
    // 抛一枚硬币
    const isHeads = Boolean(Math.round(Math.random()));
    if(isHeads) return 'yay';
    throw Error('Boo!');
}
async function foo() {
    try {
        return await waitAndMaybeReject();
    }
    catch (e) {
        return 'caught';
    }
}

拆开来看

async function foo() {
  try {
    // 等待 waitAndMaybeReject() 的结果来解决,
    // 并且将 fullfill 的值赋给 fullfilledValue:
    const fulfilledValue = await waitAndMaybeReject();
    // 如果 waitAndMaybeReject() reject了,
    // 我们的代码就会抛出异常,并且进入 catch 代码块的逻辑。
    // 否则,这里的代码就会继续运行下面的语句:
    return fulfilledValue;
  }
  catch (e) {
    return 'caught';
  }
}

在try/catch之外的代码块中执行return await是多余的(如前所述,直接return即可),甚至Eslint还专门有规则来检测这种场景,但是在try/catch代码块之内,Eslint就允许这种操作。

参考
异步Promise及Async/Await最完整入门攻略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值