什么是JavaScript承诺和C​​#asyc-await的状态机?

时间:2017-02-23 09:49:01

标签: javascript c# promise async-await

我目前正在C#中查看async-await,并注意到与JavaScript承诺的相似之处。看看这个我看到JavaScript也支持async-await语句,并且这和promises之间有相似之处(例如,看at this blog post)。

一时兴起,我想知道JavaScript async-await的实现是什么,并发现了这个问题(Java Equivalent of C# async/await?)。

接受的答案表明async-await(我认为,承诺)是“状态机”的实现。

问题:就承诺而言,'状态机'是什么意思,并且JavaScript承诺与C#的async-await相当?

1 个答案:

答案 0 :(得分:3)

JavaScript承诺与C#Task对象相当,后者的ContinueWith函数在JavaScript中的行为类似于.then

“状态机”意味着它们通常由state和switch语句实现。状态是函数在同步运行时可以处于的位置。我认为最好看看这种转变在实践中是如何运作的。例如,假设您的运行时只能理解常规函数。异步函数类似于:

async function foo(x) {
   let y = x + 5;
   let a = await somethingAsync(y);
   let b = await somethingAsync2(a);
   return b;
}

现在,让我们看一下同步执行步骤时函数的所有位置:

async function foo(x) {
   // 1. first stage, initial
   let y = x + 5;
   let a = await somethingAsync(y);
   // 2. after first await
   let b = await somethingAsync2(a);
   // 3. after second await
   return b;
   // 4. done, with result `c`.
}

现在,由于我们的运行时只能理解同步函数 - 我们的编译器需要做一些事情来使代码成为同步函数。我们可以使它成为常规功能并保持状态吗?

let state = 1;
let waitedFor = null; // nothing waited for
let waitedForValue = null; // nothing to get from await yet.
function foo(x) {
   switch(state) {
      case 1: { 
        var y = x + 5;
        var a;
        waitedFor = somethingAsync(y); // set what we're waiting for
        return;
      }
      case 2: {
         var a = waitedForValue; 
         var b;
         waitedFor = somethingAsync(a);
         return;
      }
      case 3: {
        b = waitedFor;
        returnValue = b; // where do we put this?
        return;
      }
      default: throw new Error("Shouldn't get here");
   }
}

现在,它有点有用,但没有做任何太有趣的事情 - 我们需要实际运行它作为一个函数。让我们把状态放在一个包装器中,并在它们被解决时自动运行promises:

function foo(x) { // note, not async
  // we keep our state
  let state = 1, numStates = 3;
  let waitedFor = null; // nothing waited for
  let waitedForValue = null, returnValue = null; // nothing to get from await yet.
  // and our modified function
  function stateMachine() {
    switch(state) {
      case 1: { 
        var y = x + 5;
        var a;
        waitedFor = somethingAsync(y); // set what we're waiting for
        return;
      }
      case 2: {
         var a = waitedForValue; 
         var b;
         waitedFor = somethingAsync(a);
         return;
      }
      case 3: { 
        b = waitedFor;
        returnValue = b; // where do we put this?
        return;
      }
      default: throw new Error("Shouldn't get here");
   }
   // let's keep a promise for the return value;
   let resolve, p = new Promise(r => resolve = r); // keep a reference to the resolve
    // now let's kickStart it
   Promise.resolve().then(function pump(value) {
      stateMachine();
      state++; // the next state has progressed
      if(state === numStates) resolve(returnValue); // return the value
      return Promise.resolve(waitedFor).then(pump);
   }); 
   return p; // return the promise
}

实际上,Promise.resolve().then(...部分调用stateMachine并等待每次等待的值,直到它处于最终状态,此时它将解析(事先返回)的promise。

这对您的代码也有效what BabelTypeScript。 C#编译器的作用非常接近 - 最大的区别在于它是在一个类中。

注意我们忽略了条件,异常和循环 - 它使事情变得更复杂但不是更难(你只需要分别处理每个案例)。