ES2016(通常称为 ES7 或 ECMAScript 7)是 ECMA-262 标准(通常称为 JavaScript)的下一次演进,目前仍处于早期阶段。
异步函数是一种新的 JavaScript 功能,作为 ES2016 标准的一部分提出,尚未被任何浏览器支持。它们建立在 promises 之上。
请参阅下文,了解来自各种权威来源的这项新功能的介绍。
注意:
尽管异步函数通常被称为ES7 asynch functions(例如,为了消除它们与async.js 或asynchronous JavaScript 的歧义),但Axel Rauschmayer 推荐not calling them that,因为它只包含一个功能一旦提案达到第 4 阶段,就在下一个标准中。
异步函数目前仅处于第 3 阶段。事实上,ES2016 可能会not contain async functions(正如Felix Kling 在下面的 cmets 中指出的那样)。
来自the stage 3 proposal:
简介
在 ECMAScript 中引入 Promise 和生成器提供了一个
显着改进语言级别模型的机会
在 ECMAScript 中编写异步代码。
在此期间,Deferred Functions 也提出了类似的建议
ES6 讨论。这里的提议支持相同的用例,使用
相似或相同的语法,但直接建立在控制流之上
与生成器平行的结构,并使用承诺
返回类型,而不是定义自定义机制。
此提案的制定时间为
https://github.com/tc39/ecmascript-asyncawait。请提出问题
那里。重要的贡献仅限于 TC39 成员,但拉
欢迎并鼓励提出小问题的请求!
此提案的状态
此提案已被接受进入第 3 阶段(“候选人”)
ECMAScript spec process 2015 年 9 月。冠军
打算通过以下方式将该提案接受到第 4 阶段(“完成”)
11 月底。
示例
以下面的例子为例,首先使用 Promises 编写。这段代码
在一个元素上链接一组动画,当有一个动画时停止
动画中的异常,并返回由
最终成功执行的动画。
function chainAnimationsPromise(elem, animations) {
let ret = null;
let p = currentPromise;
for(const anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
})
}
return p.catch(function(e) {
/* ignore and keep going */
}).then(function() {
return ret;
});
}
已经有了 Promise,代码比直接的回调风格有了很大的改进,这种循环和异常处理是
具有挑战性。
Task.js 和类似的库提供了一种使用生成器的方法
进一步简化保持相同含义的代码:
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(const anim of animations) {
ret = yield anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
});
}
这是一个显着的改进。所有超出代码语义内容的 Promise 样板都被删除,并且
内部函数的主体代表用户意图。然而,有
样板的外层,用于将代码包装在额外的
生成器函数并将其传递给库以转换为承诺。
这个层需要在每个使用它的函数中重复
产生承诺的机制。这在典型的异步中很常见
Javascript 代码,消除对
剩余的样板。
使用异步函数,所有剩余的样板都被删除,
在程序文本中只留下语义上有意义的代码:
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(const anim of animations) {
ret = await anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
}
来自Jake Archibald的文章ES7 async functions:
与承诺异步
在HTML5Rocks article on promises 中,最后一个例子展示了如何
你会为一个故事加载一些 JSON 数据,然后用它来获取更多
章节的 JSON 数据,然后尽快按顺序渲染章节
当他们到达时。
代码如下:
function loadStory() {
return getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
return story.chapterURLs.map(getJSON)
.reduce(function(chain, chapterPromise) {
return chain.then(function() {
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage("All done");
}).catch(function(err) {
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
}
还不错,但是……
这次是 ES7 异步函数……
async function loadStory() {
try {
let story = await getJSON('story.json');
addHtmlToPage(story.heading);
for (let chapter of story.chapterURLs.map(getJSON)) {
addHtmlToPage((await chapter).html);
}
addTextToPage("All done");
} catch (err) {
addTextToPage("Argh, broken: " + err.message);
}
document.querySelector('.spinner').style.display = 'none';
}
使用异步函数 (full proposal),您可以在承诺上使用 await。
这会以非阻塞方式停止函数,等待承诺
解析并返回值。如果承诺拒绝,它会抛出
拒绝值,所以你可以使用catch来处理它。
编辑:我最初在箭头函数中使用await apparently that's not allowed 所以我用for 替换它
环形。 Domenic 在why await can't be
used in arrow functions 上给了我一些知识。
loadStory 返回一个承诺,所以你可以在其他异步中使用它
功能。
(async function() {
await loadStory();
console.log("Yey, story successfully loaded!");
}());
来自KoaJS 文章The Evolution of Asynchronous JavaScript:
发电机/产量
JavaScript Generators 是一个相对较新的概念,它们是
在 ES6(也称为 ES2015)中引入。
当你执行你的函数时,你可以在任何时候暂停它,计算其他东西,做其他事情,这不是很好吗?
然后返回它,即使有一些价值并继续?
这正是生成器函数为您所做的。当我们调用
生成器函数它没有开始运行,我们将不得不迭代
手动通过它。
function* foo () {
var index = 0;
while (index < 2) {
yield index++;
}
}
var bar = foo();
console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }
如果您想轻松使用生成器来编写异步
JavaScript,你也需要co。
Co 是一个基于生成器的 Node.js 和浏览器控制流,使用 Promise,让您在
不错的方式。
使用co,我们之前的示例可能如下所示:
co(function* (){
yield Something.save();
}).then(function() {
// success
})
.catch(function(err) {
//error handling
});
您可能会问:并行运行的操作呢?答案是
比您想象的要简单(实际上它只是一个
Promise.all):
yield [Something.save(), Otherthing.save()];
异步/等待
异步函数是在 ES7 中引入的 - 目前仅可用
使用像 babel 这样的编译器。 (免责声明:现在我们正在谈论
async 关键字,而不是 async 包)
简而言之,使用 async 关键字我们可以做我们正在做的事情
co 和生成器的组合 - 黑客除外。
在 async 函数的底层使用 Promise - 这就是为什么
异步函数将返回 Promise。