【问题标题】:What is a state machine in terms of JavaScript promises and C# asyc-await?就 JavaScript Promise 和 C# async-await 而言,什么是状态机?
【发布时间】:2017-02-23 09:49:01
【问题描述】:

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

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

公认的答案表明async-await(我猜,还有promises)是“状态机”的实现。

问题:就承诺而言,“状态机”是什么意思,JavaScript 承诺是否可以与 C# 的 async-await 相媲美?

【问题讨论】:

  • 我最近在这里读到了一个关于 .Netyieldasync/await 的实现的问题。答案在状态机和一些伪代码方面都进行了讨论。我不确定这是否是最近的问题。 (我可能是偶然导航到它的)。它不一定会回答你的问题,但它是一个很好的读物,我似乎无法找到它(在我的手机上搜索)。也许有更好的搜索技能的人可以在知道主题的情况下找到它。
  • 这就是我来到这里的原因twitter.com/rauschma/status/1026954063924084737(Axel Rauschmayer 在其他人中推特关于 NPM 包的编译目标)

标签: javascript c# promise async-await


【解决方案1】:

JavaScript 承诺类似于 C# Task 对象,后者具有 ContinueWith 函数,其行为类似于 JavaScript 中的 .then

“状态机”是指它们通常由状态和 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");
   }
}

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

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 并等待每次等待的值,直到它处于最终状态,此时它解决了(预先返回的)承诺。

这实际上也是what BabelTypeScript 对您的代码执行的操作。 C# 编译器所做的非常接近 - 最大的不同是它被放在一个类中。

请注意,我们在这里忽略了条件、异常和循环 - 它使事情变得有点复杂但并不难(您只需要分别处理每种情况)。

【讨论】:

  • 谢谢。作为一般“状态机”概念的新手,在阅读此答案之前,这是一个很好的问题:stackoverflow.com/questions/31100824/finite-state-machine-in-c
  • 说状态机实际上是the theoretical mapping of all of a program's possible conditions in terms of the operations that program can perform对吗?
  • 此上下文中的状态机只是在“状态”之间转换的东西(在这种情况下,是 switch 语句的部分)。
  • 说状态机本身是一个“抽象概念”是否正确,这意味着它只是逻辑的表示?可以说switch语句是状态机的实现吗?
猜你喜欢
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 2020-03-01
  • 2019-08-17
  • 2014-04-17
  • 2019-08-11
  • 1970-01-01
  • 2017-09-11
相关资源
最近更新 更多