当前位置:K88软件开发文章中心编程语言JavaScriptECMAScript → 文章内容

ECMAScript 6 异步操作和Async函数

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 15:38:39

关系,最好让它们同时触发。let foo = await getFoo();let bar = await getBar();上面代码中,getFoo和getBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发。// 写法一let [foo, bar] = await Promise.all([getFoo(), getBar()]);// 写法二let fooPromise = getFoo();let barPromise = getBar();let foo = await fooPromise;let bar = await barPromise;上面两种写法,getFoo和getBar都是同时触发,这样就会缩短程序的执行时间。第三点,await命令只能用在async函数之中,如果用在普通函数,就会报错。async function dbFuc(db) { let docs = [{}, {}, {}]; // 报错 docs.forEach(function (doc) { await db.post(doc); });}上面代码会报错,因为await用在普通函数之中了。但是,如果将forEach方法的参数改成async函数,也有问题。async function dbFuc(db) { let docs = [{}, {}, {}]; // 可能得到错误结果 docs.forEach(async function (doc) { await db.post(doc); });}上面代码可能不会正常工作,原因是这时三个db.post操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用for循环。async function dbFuc(db) { let docs = [{}, {}, {}]; for (let doc of docs) { await db.post(doc); }}如果确实希望多个请求并发执行,可以使用Promise.all方法。async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = await Promise.all(promises); console.log(results);}// 或者使用下面的写法async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results);}ES6将await增加为保留字。使用这个词作为标识符,在ES5是合法的,在ES6将抛出SyntaxError。与Promise、Generator的比较我们通过一个例子,来看Async函数与Promise、Generator函数的区别。假定某个DOM元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。首先是Promise的写法。function chainAnimationsPromise(elem, animations) { // 变量ret用来保存上一个动画的返回值 var ret = null; // 新建一个空的Promise var p = Promise.resolve(); // 使用then方法,添加所有动画 for(var 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*() { var ret = null; try { for(var anim of animations) { ret = yield anim(elem); } } catch(e) { /* 忽略错误,继续执行 */ } return ret; });}上面代码使用Generator函数遍历了每个动画,语义比Promise写法更清晰,用户定义的操作全部都出现在spawn函数的内部。这个写法的问题在于,必须有一个任务运行器,自动执行Generator函数,上面代码的spawn函数就是自动执行器,它返回一个Promise对象,而且必须保证yield语句后面的表达式,必须返回一个Promise。最后是Async函数的写法。async function chainAnimationsAsync(elem, animations) { var ret = null; try { for(var anim of animations) { ret = await anim(elem); } } catch(e) { /* 忽略错误,继续执行 */ } return ret;}可以看到Async函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将Generator写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。如果使用Generator写法,自动执行器需要用户自己提供。

上一页  [1] [2] [3] [4] [5] [6] 


ECMAScript 6 异步操作和Async函数