2017-02-23 226 views
4

В настоящее время я смотрю async-await на C# и заметил сходство с обещаниями JavaScript. В этом я вижу, что JavaScript также будет поддерживать операторы async-await и что есть сходства между этим и обещаниями (например, посмотрите at this blog post).Что такое машина состояния с точки зрения обещаний JavaScript и C# asyc-wait?

По прихоти, я задавался вопросом, в чем была реализация JavaScript async-await и нашла этот вопрос (Java Equivalent of C# async/await?).

Принятый ответ предполагает, что async-await (и, по моему мнению, обещания) являются реализациями «государственной машины».

Вопрос: Что подразумевается под «государственной машиной» с точки зрения обещаний, а также обещаниями JavaScript, сопоставимыми с C# async-await?

+0

Я недавно прочитал вопрос, который задал вопрос об осуществлении .Net'yield' и 'async/await'. Ответ обсуждался как с точки зрения государственных машин, так и с некоторым псевдокодом. Я не уверен, был ли это недавний вопрос. (Возможно, я мог случайно перейти к нему). Это не обязательно ответит на ваш вопрос, но это было очень хорошо читать по этому вопросу, я просто не могу найти его (поиск по моему телефону). Возможно, кто-то с лучшими навыками поиска может найти его, зная предмет. – pinkfloydx33

ответ

3

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# очень близок - с большой разницей в том, что он помещается в класс.

Обратите внимание, что мы игнорируем условные обозначения, исключения и циклы здесь - это делает вещи немного сложнее, но не намного сложнее (вам просто нужно обрабатывать каждый случай отдельно).

+0

Спасибо.Как кто-то, кто не знает идею «государственных машин» в целом, это хороший вопрос, который нужно прочитать перед тем, как прочитать этот ответ: http://stackoverflow.com/questions/31100824/finite-state-machine-in-c –

+0

Правильно ли говорить, что конечный автомат является «теоретическим отображением всех возможных условий программы в отношении операций, которые может выполнять программа»? –

+0

Конечный автомат в этом контексте является лишь переходом между «состояниями» (в данном случае частями оператора switch). –

Смежные вопросы