深入理解async函数

含义及作用

引入了函数,使得异步操作变得更加方便.async函数就是将Generator函数的星号(*)替换成async,将yield替换成await,仅此而已.async函数对Generator函数的改进,体现在以下四点.

  • 内置执行器
  • 更好的语义
  • 更广的适用性
  • 返回值是promise

基本用法

async函数返回一个Promise对象,可以使用then方法添加回调函数,当函数执行的时候,一旦遇到await就会先返回等到异步操作完成,再接着执行函数体内后面的语句.

async function getStockPriceByName(name) {
const symbol = await getStockPriceByName(name);
const stockPrice = await getStockPriceByName(symbol);
return stockPrice;
}

getStockPriceByName("goog").then(function(result) {
	console.log(result);
})

async函数返回的promise对象,必须等到内部所有await命令后面的promise对象执行完,才会发生状态变化除非遇到return语句或者抛出错误.也就是说,只有等async函数内部的异步操作对象执行完,才会执行then方法制定的回调函数

async function getTitle(url) {
let response = await fetch(url);
let html = await resoponse.text();
return html.match(/<title>([\s\S] + ) <\/title>/i)[i];
}

getTitle('https://tc39.github.io/ecma262/').then(console.log)

正常情况下,await命令后面是一个Promise对象,返回该对象的结果.如果不是promise对象,就直接返回对应的值await命令后面是一个thenable对象(即定义then的对象),那么await会将其等同于Promise对象

class Sleep{
    constructor(timeout){
        this.timout=timout;
    }
    then(resolve,reject){
        const startTime = Date.now();
        setTimeout(
            () => resolve(Date.now() - startTime),
            this.timeout
        );
    }
}

(async () => {
    const.actualTime = await new Sleep(1000);
    console.log(actualTime);
})();

错误处理

使用try…catch结构,实现多次重复尝试,await后面的promise对象会抛出一个错误对象,导致catch方法的回调函数被配出的错误对象调用.

const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
	let i;
	for (i = 0; i < NUM_RETRIES; ++i) {
		try{
			await superagent.get('http://google.com/this-throw-an-error');
			break;
		} catch (err) {

		}
	}
	console.log(i);
}

test();

与其他异步处理方法的比较:

async函数的实现原理:将Gennerator函数和自动执行器,包装在一个函数里

async函数与Promise,Generator函数的比较案例:

假定某个DOM元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个,如果当中有一个动画出错,就不在往下执行,返回上一个成功执行的动画的返回值.

Promise的写法

function chainAnimationsPromise(elem, animations) {

//变量ret用来保存上一个动画的返回值
let ret = null;

//新建一个空的promise
let p = Promise.resolve();

//使用then方法。添加所有动画
for(let anim of animations) {
	p = p.then(function(val) {
		ret = val;
		return anim(elem);
	});
}

//返回一个部署了错误捕捉机制的Promise
return p.catch(function(e) {
	//忽略错误,继续执行
}).then(function() {
	return ret;
});
}

虽然Promise的写法比回调函数的写法大大改进,但是一眼看上去,代码完全都是Promise的API(then,catch等等),操作本身的语义反而不容易看出来.

Generator函数的写法

function chainAnimationsGenerator(elem, animations) {
    return spawn(function*(){
        let ret = null;
        try{
            for(let anim of animations){
                ret == yield anim(elem);
            }
        }catch(e){
            //忽略错误,继续执行
        }
        return ret;
    });
}

虽然map方法的参数是async函数,但它是并发执行的,因为只有async函数内部是继发执行,外部不受影响.后面的for…of循环内部使用await,因此实现了按顺序输出.

for await…of

for…of循环用于遍历同步的Iterator接口,新引入的for await…of循环,则是用于遍历异步的Iterator接口

async function f(){
    for await (const x of createAsyncInterable(['a','b'])){
        console.log(x);
    }
}
//a
//b

注意:

(1) await命令后面的promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中

async function myFunction(){
    try{
        await somethingThatReturnAPromise();
    }catch(err){
        console.log(err);
    }
}

//另一种写法
async function myFunction(){
    await somethingThatReturnAPromise().catch(function(err){
        console.log(err);
    });
}

(2)多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时出发,继发写法(不推荐):比较耗时,执行完一个才能执行下一个

let foo = await getFoo();
let bar = await getBar();

同时触发(推荐):缩短程序的执行时间

//写法一
let [foo,bar] = await Promise.all([getFoo(),getBar()]);
//写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

(3)await命令只能在async函数之中,如果在普通函数就会报错

async function dbFunc(db) {
    //报错
    docs.forEach(function (doc){
        await db.post(doc);
    });
}
//报错,因为await用在普通函数之中了

function dbFunc(db){
    //这里你需要async
    let docs = [{},{},{}];
    
    //可能得到错误结果
    docs.forEach(async function(doc){
        await db.post(doc);
    });
}

//原因是这时三个db.post操作将是并发执行,也就是同时执行,而不是继发执行
//正确写法是采用for循环

async function dbFunc(db){
    let docs = [{},{},{}];
    
    for(let doc of docs){
        await db.post(doc);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值