JavaScript-обещания сопоставимы с объектами C# Task
, которые имеют функцию ContinueWith
, которая ведет себя как .then
в JavaScript.
Под «государственными машинами» это означает, что они обычно реализуются с помощью состояния и оператора 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# очень близок - с большой разницей в том, что он помещается в класс.
Обратите внимание, что мы игнорируем условные обозначения, исключения и циклы здесь - это делает вещи немного сложнее, но не намного сложнее (вам просто нужно обрабатывать каждый случай отдельно).
Я недавно прочитал вопрос, который задал вопрос об осуществлении .Net'yield' и 'async/await'. Ответ обсуждался как с точки зрения государственных машин, так и с некоторым псевдокодом. Я не уверен, был ли это недавний вопрос. (Возможно, я мог случайно перейти к нему). Это не обязательно ответит на ваш вопрос, но это было очень хорошо читать по этому вопросу, я просто не могу найти его (поиск по моему телефону). Возможно, кто-то с лучшими навыками поиска может найти его, зная предмет. – pinkfloydx33