简体   繁体   English

ES2017 - 异步与收益率

[英]ES2017 - Async vs. Yield

I am confused about the current discussion of adding async functions and the keyword await to the next EcmaScript. 我对当前关于添加异步函数和关键字await下一个EcmaScript的讨论感到困惑。

I do not understand why it is necessary to have the async keyword before the function keyword. 我不明白为什么有必要在function关键字之前使用async关键字。

From my point of view the await keyword to wait for a result of a generator or promise done , a function's return should be enough. 从我的观点来看, await关键字等待了发电机或承诺的结果,函数的return应该是足够的。

await should simple be usable within normal functions and generator functions with no additional async marker. await应该可以在普通函数和生成器函数中使用,而不需要额外的async标记。

And if I need to create a function what should be usable as an result for an await , I simply use a promise. 如果我需要创建一个函数作为await的结果,我只需使用一个promise。

My reason for asking is this good explanation, where the following example comes from: 我的理由是这个很好的解释,下面的例子来自:

async function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // some more logic
}

It also could be done as normal function, if the execution of a function will wait for finishing the hole function until all awaits are fulfilled. 它也可以作为普通函数完成,如果函数的执行将等待完成孔函数,直到满足所有等待。

function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // return because createUser() and getFacebookFriends() and maybe inviteFacebookFriends() finished their awaited result.

}

In my opinion the whole function execution is holding until the next tick (await fulfillment) is done. 在我看来,整个功能执行一直持续到下一个滴答(等待履行)完成。 The difference to Generator-Function is that the next() is triggering and changing the object's value and done field. 与Generator-Function的不同之处在于next()正在触发并更改对象的值和完成字段。 A function instead will simple give back the result when it is done and the trigger is a function internal trigger like a while-loop. 一个函数将简单地返回结果,并且触发器是一个函数内部触发器,如while循环。

I do not understand why it is necessary to have the async keyword before the function keyword. 我不明白为什么有必要在function关键字之前使用async关键字。

For the same reason that we have the * symbol before generator functions: They mark the function as extraordinary. 出于同样的原因,我们在生成器函数之前有*符号:它们将函数标记为非凡。 They are quite similar in that regard - they add a visual marker that the body of this function does not run to completion by itself, but can be interleaved arbitrarily with other code. 它们在这方面非常相似 - 它们添加了一个可视标记,该函数的主体本身不会完成运行,但可以与其他代码任意交错。

  • The * denotes a generator function, which will always return a generator that can be advanced (and stopped) from outside by consuming it similar to an iterator. *表示一个生成器函数,它总是返回一个可以从外部进行推进(和停止)的生成器,类似于迭代器。
  • The async denotes an asynchronous function, which will always return a promise that depends on other promises and whose execution is concurrent to other asynchronous operations (and might be cancelled from outside). async表示一个异步函数,它将始终返回一个依赖于其他promises的promise,其执行与其他异步操作并发(并且可能从外部取消)。

It's true that the keyword is not strictly necessary and the kind of the function could be determined by whether the respective keywords ( yield(*) / await ) appear in its body, but that would lead to less maintainable code: 确实,关键字不是绝对必要的,函数的类型可以通过相应的关键字( yield(*) / await )是否出现在其正文中来确定,但这会导致代码的可维护性降低:

  • less comprehensible, because you need to scan the whole body to determine the kind 不易理解,因为你需要扫描整个身体来确定那种
  • more errorprone, because it's easy to break a function by adding/removing those keywords without getting a syntax error 更多的errorprone,因为通过添加/删除这些关键字而不会出现语法错误很容易破坏功能

a normal function, whose execution will wait for finishing the hole body until all awaits are fulfilled 一个正常的函数,执行将等待完成孔体直到满足所有等待

That sounds like you want a blocking function, which is a very bad idea in a concurrent setting. 这听起来像你想要一个阻塞功能,这在并发设置中是一个非常糟糕的主意

By marking a function as async , you're telling JS to always return a Promise. 通过将函数标记为async ,您告诉JS始终返回Promise。

Because it will always return a Promise, it can also await on promises inside of its own block. 因为它总会返回一个Promise,它也可以等待它自己的块内的promise。 Imagine it like one giant Promise chain - what happens internally to the function gets effectively gets bolted on to its internal .then() block, and what's returned is the final .then() in the chain. 想象它就像一个巨大的Promise链 - 函数内部发生的事情有效地被固定到它的内部.then()块,返回的是链中的最终.then()

For example, this function... 例如,这个功能......

async function test() {
  return 'hello world';
}

... returns a Promise. ...返回一个承诺。 So you can execute it like one, .then() and all. 所以你可以像一个, .then()和所有那样执行它。

test().then(message => {
  // message = 'hello world'
});

So... 所以...

async function test() {
  const user = await getUser();
  const report = await user.getReport();
  report.read = true
  return report;
}

Is roughly analogous to... 大致类似于......

function test() {
  return getUser().then(function (user) {
    return user.getReport().then(function (report) {
      report.read = true;
      return report;
    });
  });
}

In both cases, the callback passed to test().then() will receive report as its first parameter. 在这两种情况下,传递给test().then()的回调将接收report作为其第一个参数。

Generators (ie marking a function * and using the yield keyword) are a different concept altogether. 生成器(即标记函数*和使用yield关键字)是完全不同的概念。 They don't use Promises. 他们不使用Promises。 They effectively allow you to 'jump' between different portions of your code, yielding a result from inside of a function and then jumping back to that point and resuming for the next yield block. 它们有效地允许您在代码的不同部分之间“跳转”,从函数内部生成结果,然后跳回到该点并恢复到下一个yield块。

Although they feel somewhat similar (ie 'halting' execution until something happens somewhere else), async/await only gives you that illusion because it messes with the internal ordering of Promise execution . 虽然他们觉得有些相似(即'暂停'执行,直到某些事情发生在其他地方), async/await只会给你这种错觉,因为它与Promise执行的内部顺序混淆 It's not actually waiting - it's just shuffling when the callbacks happen. 实际上并没有等待 - 当回调发生时它只是在洗牌。

Generators, by contrast, are implemented differently so that the generator can maintain state and be iterated over. 相反,生成器的实现方式不同,因此生成器可以维护状态并进行迭代。 Again, nothing to do with Promises. 再一次,与Promises无关。

The line is further blurred because at the current time of writing, support for async/await is scare; 这条线路进一步模糊,因为在目前的写作时,对async / await的支持很吓人; Chakracore supports it natively, and V8 has it coming soon . Chakracore原生支持它, V8即将推出 In the meantime, transpilers like Babel allow you to write async/await and convert the code to generators . 与此同时,像Babel这样的转换允许你编写async/await并将代码转换为生成器 It's a mistake to conclude that generators and async/await are therefore the same; 结论发电机和异步/等待是相同的是错误的; they're not... it just so happens that you can bastardize how yield works alongside Promises to get a similar result. 它们不是......只是碰巧你可以将yield与Promises一起工作以获得类似的结果。

Update: November 2017 更新:2017年11月

Node LTS now has native async/await support, so you ought never to need to use generators to simulate Promises. 节点LTS现在具有本机async/await支持,因此您永远不需要使用生成器来模拟Promises。

These answers all give valid arguments for why the async keyword is a good thing, but none of them actually mentions the real reason why it had to be added to the spec. 这些答案都给出了为什么async关键字是好事的有效论据,但它们都没有提到为什么必须将它添加到规范中的真正原因。

The reason is that this was a valid JS pre-ES7 原因是这是一个有效的JS pre-ES7

function await(x) {
  return 'awaiting ' + x
}

function foo() {
  return(await(42))
}

According to your logic, would foo() return Promise{42} or "awaiting 42" ? 根据你的逻辑, foo()返回Promise{42}还是"awaiting 42" (returning a Promise would break backward compatibility) (返回Promise会破坏向后兼容性)

So the answer is: await is a regular identifier and it's only treated as a keyword inside async functions, so they have to be marked in some way. 所以答案是: await是一个常规标识符,它只被视为异步函数中的关键字,因此必须以某种方式标记它们。

Fun fact: the original spec proposed more lightweight function^ foo() {} for async syntax. 有趣的事实:原始规范为异步语法提出了更轻量级的function^ foo() {}

The reason for the async keyword in front is simple so you know that return value will be transformed into a promise. 前面的async关键字的原因很简单,因此您知道返回值将转换为promise。 If no keyword how would the Interpreter know to do this. 如果没有关键字,解释器将如何知道这样做。 I think this was first introduce in C# and EcmaScript is taking a loot of stuff from TypeScript. 我认为这是首次在C#中引入,而EcmaScript正在从TypeScript中获取一些东西。 TypeScript and C# are conceived by Anders Hejlsberg and are similar. TypeScript和C#由Anders Hejlsberg构思并且类似。 lets say you have a function (this one is just to have some asynchronous work) 假设你有一个函数(这只是为了有一些异步工作)

 function timeoutPromise() {  
     return (new Promise(function(resolve, reject) {
         var random = Math.random()*1000;
         setTimeout(
             function() {
                 resolve(random);
             }, random);
     }));
 }

this function will make us wait for a random time and return a Promise (if you use jQuery Promise is similar to Deferred) object. 这个函数会让我们等待一个随机时间并返回一个Promise(如果你使用jQuery Promise类似于Deferred)对象。 To use this function today you would write something like this 今天要使用这个功能你会写这样的东西

function test(){
    timeoutPromise().then(function(waited){
        console.log('I waited' + waited);
    });
}

And this is fine. 这很好。 Now lets try to return the log message 现在让我们尝试返回日志消息

function test(){
    return timeoutPromise().then(function(waited){
        var message = 'I waited' + waited;
        console.log(message);
        return message; //this is where jQuery Deferred is different then a Promise and better in my opinion
    });
}

Ok this is not bad but there are two return statements and a function in the code. 好吧这不错,但代码中有两个return语句和一个函数。

Now with async this will look like this 现在使用异步,这将是这样的

  async function test(){
      var message = 'I waited' +  (await timeoutPromise());
      console.log(message);
      return message;
  }

The code is short and inline. 代码很简短,内联。 If you written a lot of .then() or . 如果你写了很多.then()或。 done() you know how unreadable the code can get. done()你知道代码有多难以理解。

Now why the async keyword in front of function. 现在为什么async关键字在函数前面。 Well this is to indicate that your return value is not what is returned. 那么这是为了表明你的返回值不是返回的值。 In theory you could write this(This can be done in c# I don't know if js will allow since it's not done). 理论上你可以写这个(这可以在c#中完成我不知道js是否允许,因为它没有完成)。

 async function test(wait){
     if(wait == true){
         return await timeoutPromise();
     }
     return 5;                
 }

you see, you return a number but the actual return will be a Promise you don't have to use return new Promise(function(resolve, reject) { resolve(5);}; Since you can't await a number only a Promise await test(false) will throw an exception and await test(true) will not if you don't indicate async in front. 你看,你返回一个数字,但实际的回报将是一个你不必使用的return new Promise(function(resolve, reject) { resolve(5);};因为你不能等待一个数字只有一个Promise await test(false)将抛出异常,如果你没有在前面指出异步,则await test(true)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM