ES7的async和await,目前最为简略的异步解决方案

随着js的发展,在解决回调地狱问题的方案上,解决方案逐渐更新,有promise、generator和现在的async都是比较常见的;
1.Promise
这个解决方案就是把异步用同步的方式写出来,一步一步的.then()方法,前一个.then()执行完之后,继续执行下一个.then();

function timeout (time) {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            res('this is a returnDate');
        },time)
    })
};

time(5000)
.then((data)=>{console.log(data)})
.then(()=>{console.log('end')})
...

这就是promise的异步解决方案看起来还是很简单的,其实只是以你为逻辑简单;

2.Generator
Generator函数是个异步管理器,这里要提到一个协程的概念,先不用管协程是什么鬼,先来介绍一下yield命令,它是Generator函数中的分水岭,在函数内部起执行权转义的功能,什么是执行权?好吧,这就是在Generator函数内部遇到yield命令,那么就不往下执行了,就把执行权交出来给别的函数,等别的函数执行之后返回结果了,在返还执行权,继续向下执行Generator函数的语句;

function generator () {
    // 代码A;
    var f = yield readFile(fileA);
    // 代码A;
}

以上代码中,当函数执行的时候分一下步骤:
a.开始执行代码A;
b.代码A执行到一半,遇到yield命令,暂停执行,开始执行,执行权交给yield命令后面的函数;
c.当yield函数执行完之后,交还执行权;
d.继续执行yield命令下面的代码A;
在这个过程中,代码段A被分成两段执行,代码段A叫做协程A,readFile()函数叫做协程B,协程A是异步的;
再来举个例子:

function* gen(x){
    var y = yield x+2;
    return y
}

var g = gen(1);
g.next() // { value:3, done:false }
g.next() // { value:undefined, done:ture }

a.调用Generator函数并不会像其他普通函数一样返回函数值,它会返回一个内部指针——g;
b.调用内部指针中的next方法,会移动指针分配执行权去手动执行函数;返回结果会是一个对象,value字段对应运算值,done字段是布尔类型,说明函数是否执行完;
c.上面代码中,第一次调用next方法,函数执行到x+2,值返回给value属性;第二次调用next方法,执行代码是return y,这时y并没有值,只是定义了,所以第二次vlaue的值是undefined
d.当然next方法也是可以传值的,如下:

var g = gen(1);
g.next() // { value:3, done:false }
g.next(2) // { value:2, done:ture }

这时第二个next方法带有参数2,这个参数会传到Generator函数内部,作为上个协程任务的返回结果被函数体内的变量y接收,因此value的值是2;

对了这里在补一句,从上可以看出Generator函数是需要手动执行的,那么有没有可以让其自执行的办法呢,有~
co模块小工具可以让Generator函数自执行,只要把其当参数传进co中;

var co = require('co');
co(gen);

3.async函数
这个es7草案,说实话也是最简单的异步解决方案,问其原理,其实是Generator函数的语法糖;
a:

function timeout (time) {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            res();
        },time)
    })
}

let start = async function () {
    console.log('start');
    let data = await timeout(5000);
    console.log('end');
}

执行结果是:
先打印出start,然后转为timeout函数执行,执行时间为5s,之后返回打印出end
是不是跟Generator函数很相似,awaityield命令作用一样~

b.当然了,也是可以获取到返回值的:

function timeout (time) {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            res('this is a returnDate');
        },time)
    })
}

let start = async function () {
    console.log('start');
    let data = await timeout(5000);
    console.log(data);
}

这样,5s后打印出来的就是this is a returnDate;

c.当然,也可以捕获错误:

function timeout (time) {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            rej('this is an err');
        },time)
    })
}

let start = async function () {
    console.log('start');
    try {
        let data = await timeout(5000);
        console.log(data);
    } catch (err) {
        console.log(err);
    }

}

这里timeout函数返回一个错误,那么被try...catch...语句中的catch捕获,则不执行try中的代码,直接执行catch中的代码,打印出错误;

d.当然了,这里也是可以循环多执行await的

function timeout (time) {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            rej('this is an err');
        },time)
    })
}

let start = async function () {
    for(let i=0; i<=10; i++) {
        console.log(`这是第${i}次等待`);
        await timeout(5000);
    }
}

这里指出非常重要的一点,await命令必须要在async函数的上下文中,也就是说当await命令所在的环境中this的指向不是async的时候,会报错!
所以这里要用for循环,for…of循环,不能用map,forEach方法等;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值