您的位置:首页 > 大数据 > 人工智能

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

2017-03-30 18:57 801 查看
随着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函数很相似,
await
yield
命令作用一样~

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方法等;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: