【问题标题】:What are ES7 Async functions? [closed]什么是 ES7 异步函数? [关闭]
【发布时间】:2016-06-05 10:36:04
【问题描述】:

我已经使用 Babel 有一段时间了,我很喜欢它。但是,在列出支持的功能的主页上,它显示Async functions

我做了很多谷歌搜索,我似乎只能理解它是一个 ES7 特性。

请问什么是 ES7 异步函数?

【问题讨论】:

  • 异步函数是一个可怕的想法,让你放弃承诺并逐行编写异步代码,而不必担心事情何时完成等。
  • @FrédéricHamidi - 我当然愿意,但这并不意味着我认为所有的变化都是好的,而在我看来,这不是。
  • “ES7 Async”搜索 ►A Primer on ES7 Async Functions 据我所知,它似乎解释了它的所有内容。
  • @adeneo: async/await 不会放弃承诺。它拥抱他们。它使具有复杂控制流的 Promise 代码更易于阅读和编写。
  • @adeneo: Like generators,它使您能够使用以前几乎无法使用的各种控制结构。并且async 函数仍然可以使用,它们每个都返回一个承诺!它们可以完全透明地与普通的 promise-returning 函数交换,就像生成器函数可以与迭代器返回函数一样(唯一的区别是 .toString())。

标签: javascript async-await ecmascript-next


【解决方案1】:

ES2016(通常称为 ES7 或 ECMAScript 7)是 ECMA-262 标准(通常称为 JavaScript)的下一次演进,目前仍处于早期阶段。

异步函数是一种新的 JavaScript 功能,作为 ES2016 标准的一部分提出,尚未被任何浏览器支持。它们建立在 promises 之上。

请参阅下文,了解来自各种权威来源的这项新功能的介绍。

注意:

尽管异步函数通常被称为ES7 asynch functions(例如,为了消除它们与async.jsasynchronous 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

【讨论】:

  • 为什么这个答案会被否决?!
  • 我的两分钱:我考虑了几分钟,最终否决了它,因为它是来自不同来源的摘录的汇总,几乎没有原始内容。我承认您在格式化方面付出的努力,但我仍然认为我们不应该鼓励这样做。
  • @FrédéricHamidi:好点。时间会证明一切!再次感谢您的反馈!
  • 仅供参考,async/await不会成为 ES7 (ES2016) 的一部分。只有第 4 阶段的提案是。
  • @FelixKling :谢谢!我在回答中添加了一条注释,以反映您在 cmets 中提出的观点,以及涉及即将推出的 Ecmascript 命名的各种小改进标准。
【解决方案2】:

Async Await 与 ES6 Promises 一起工作。您可以将它们视为使用 Promises 编写类似同步代码的一种方式。

async 关键字标记为将进行异步调用的方法。 await 关键字标记实际调用。

使用 Promise,您需要将方法传递给 Promise 的 .then() 方法以处理结果。

function doSomethingAsync() {
    return new Promise((resolve, reject) => {
        // call Rest service and resolve here
    })
}

function printResult() {
    doSomethingAsync()
        .then(result => console.log(result));
}

这一切都很好。使用Async/Await,我们可以编写最后一个函数。

async function printResult() {
    let result = await doSomethingAsync();
    console.log(result);
}

这样做的好处是它简单地减少了对回调的需求。

更多信息请见:https://www.twilio.com/blog/2015/10/asyncawait-the-hero-javascript-deserved.html

【讨论】:

  • 请在投反对票时发表评论。如果您因为不喜欢 async/await 的概念而投反对票,也请告诉我?
  • 仅供参考,Promises 是 ES6 (ES2015) 的一部分,async/await 不会 将成为 ES7(ES2016) 的一部分。
  • 感谢这个例子。我终于意识到async 本身并不是为了使函数异步。这需要使用Promise 来完成。 async 仅将某些函数标记为能够使用 await 并使对 async func 的函数调用显示为同步。
猜你喜欢
  • 1970-01-01
  • 2016-03-01
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 2016-04-16
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
相关资源
最近更新 更多