我目前正在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
相当?
答案 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 Babel或TypeScript。 C#编译器的作用非常接近 - 最大的区别在于它是在一个类中。
注意我们忽略了条件,异常和循环 - 它使事情变得更复杂但不是更难(你只需要分别处理每个案例)。