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 Babel 或TypeScript 对您的代码执行的操作。 C# 编译器所做的非常接近 - 最大的不同是它被放在一个类中。
请注意,我们在这里忽略了条件、异常和循环 - 它使事情变得有点复杂但并不难(您只需要分别处理每种情况)。