Псевдосинхронное программирование в Javascript, но есть ли лучшая реализация? - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть прототип уроков JavaScript-кодирования для маленьких детей (8-10 лет), который основан на анимации. Учебный скрипт позволяет своим пользователям программировать синхронно, например

draw(something);
wait(some time); 
draw(something_else);

Синхронное программирование выглядит намного удобнее, чем обычная техника JavaScript, но за сценой стоит асинхронное / ожидание, и оно не застревает в браузере.

Вы можете попробовать, как это работает, на http://codepegs.com/ и найти объяснение на http://codepegs.com/cphelp.html (выделите Таймерные функции ).

Асинхронное ожидание очень сдерживающее. Можно сделать гораздо больше, но перед рефакторингом системы позвольте мне спросить, знаете ли вы о существующем решении для псевдосинхронного программирования на JavaScript, которое я мог бы использовать?

Я пытался искать, и ответы были как ни в коем случае. Вот почему я привел пример.

PS: Извините, я должен добавить пост-скриптум. Я попросил предложить более сложную реализацию. В принципе это было сделано год назад. Это было грубо, но это работает. Мне это не нравится по многим причинам, но я решил спросить, прежде чем начинать новый этап программирования.

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

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

Если все остальное не сработает, вы все равно можете написать свой собственный транспортер JavaScript на самом JavaScript:

Вы можете сделать свой код многообещающим, а затем просто перенести программу на использование async / await:

  function execute(context, code) {
    let result = "";
    for(const line of code.split("\n"))) {
      if(["if", "else", "var", "for", "while"].some(keyword => line.includes(keyword)) {
        result += line + "\n";
      } else {
        result += "await " + line + "\n";
      }
    }
    with(context) { 
       return eval(`(async function() { ${result} })()`);
     }
  }

Затем просто передайте код пользователя на выполнение:

  execute({
    async draw() { /*...*/ },
    async wait(ms) { await new Promise(res => setTimeout(res, ms)); },
  },
  `draw(something);
   wait(some time); 
   draw(something_else);`
 );

Это просто, чтобы дать вам основную идею, но это работает довольно хорошо .


Или другой подход может заключаться в создании итератора, который позволяет вам проходить код построчно:

  let continuation = Promise.resolve();

  function wait(ms) { continuation = new Promise(resolve => setTimeout(resolve, ms)); }
  function draw() { /*...*/ }

   function execute( code) {
     const iterator = eval("(function* () {" + code.split("\n").join("\nyield;\n") + "})();");
    function next() {
      const { value, done } = iterator.next();
      if(done) return;
      continuation.then(next);
    }
 }

  execute(`
    console.log("wait a second....");
    wait(1000);
    console.log("done!");
 `);

Это также работает , и я полагаю, что это на самом деле довольно хороший метод работы, он потерпит неудачу, только если код содержит многострочные строки / функции.

0 голосов
/ 03 ноября 2018

По предложению Берги, было бы более элегантно фактически выполнить код синхронно и поместить все изменения в очередь, тогда вы можете медленно воспроизвести изменения:

  const queue = [];

  function draw(text) { queue.push({command: "draw", value: text }); }
  function wait(value) { queue.push({ command: "delay", value }); }

  async function end() {
    for(const { command, value } of queue) {
       switch(command) {
          case "draw":
            console.log(value);
            break;
         case "delay":
            await new Promise(res => setTimeout(res, value));
            break;
      }
   }
}

// Your code:
draw("And you get...");
wait(1000);
draw("nothing :/");
end();
0 голосов
/ 03 ноября 2018

Нет надежного способа синхронного ввода-вывода в интерфейсном JS. Существует синхронный AJAX, но WebWorkers, setTimeout, WebSockets и т. Д. Всегда асинхронны.

Так что вам понадобится async/await для получения шаблонов кодирования в синхронном стиле.

Есть еще один способ, вы в основном создаете очередь обещаний:

enqueue(function foo(){}); // put on the queue
enqueue(function bar(){}); // put on the queue
enqueue(function baz(){}); // put on the queue

это означает, что foo, bar и baz будут работать по порядку, если очередь обрабатывает только один вызов функции за раз. Но нет простого способа передать результат одной функции в другую без задействованной библиотеки. Это то, что обещания или асинхронная библиотека для.

Чтобы увидеть, как работает методология очереди, посмотрите эту библиотеку:

https://github.com/mapbox/node-sqlite3#usage

...