Я пытаюсь написать простой асинхронный код в JS, но, похоже, он не работает

function order(number) {
  console.log("Queuing order: " + number);
  for (var i = 0; i < 1000000000; i++); // kill time
  console.log("Order: " + number + " completed");
}

function takeOrder(number, cb) {
  console.log("Preparing order: " + number + "");
}
console.log("Starting to accept order");
for (var i = 0; i < 3; i++) {
  console.log("Taking order: " + i);
  takeOrder(i, order(i));
}
console.log("Job completed!");
Я пытаюсь заставить его работать, так как пока заказ (номер) занят выполнением, программа продолжает отображать сообщения "Подготовка заказа: .." и "Прием заказа: ..". Где я иду не так?

2 ответа

Решение

Я пытаюсь написать простой асинхронный код в JS...

Ничто в вашем коде не является асинхронным. Также в этом коде

takeOrder(i, order(i));

ты звонишь order и проходя в i, затем передав его возвращаемое значение (undefined) в takeOrder, Пройти order в takeOrder вместо этого удалите (i):

takeOrder(i, order);

Я пытаюсь заставить его работать, так как пока заказ (номер) занят выполнением, программа продолжает отображать сообщения "Подготовка заказа: .." и "Получение заказа: .."

JavaScript в браузерах запускается в одном основном потоке с доступом к пользовательскому интерфейсу, а затем в ноль или более созданных вами веб-рабочих потоков. Если for Цикл в вашем коде выполняется в основном потоке пользовательского интерфейса, во время его выполнения больше ничего не может произойти из-за семантики выполнения сценариев JavaScripts.

Если работа представлена for цикл является синхронным, вам не нужно ничего делать, просто ваша симуляция с использованием for петля не была точной моделью вашей реальной работы. Например, если он делает запрос ajax.

Если работа представлена for цикл полностью синхронен, как ваш for цикл, я бы, наверное, разгрузить for Цикл для веб-работника:

worker.js:

self.addEventListener("message", function(e) {
  if (e.data && e.data.command == "go") {
    for (var i = 0; i < 1000000000; i++); // kill time
    self.postMessage({command: "log", message: "Order: " + e.data.order + " completed"});
  }
});

Ваш основной файл JS:

function order(number) {
  var w = new Worker("worker.js");
  w.addEventListener("message", function(e) {
    if (e.data && e.data.command == "log") {
      console.log(e.data.message);
    }
    w = null;
  });
  console.log("Queuing order: " + number);
  w.postMessage({command: "go", order: number});
}

function takeOrder(number, cb) {
  console.log("Preparing order: " + number + "");
  cb(number);                                       // Call the callback
}
console.log("Starting to accept order");
for (var i = 0; i < 3; i++) {
  console.log("Taking order: " + i);
  takeOrder(i, order);                              // Pass order as the callback
}
console.log("Job completed!");

Это создает нового работника для каждого заказа, поэтому они могут перекрываться.

Выход:

Начиная принимать заказ
Принимая заказ: 0
Подготовка заказа: 0
Порядок очередей: 0
Принимая заказ: 1
Подготовка заказа: 1
Порядок очередей: 1
Принимая заказ: 2
Подготовка заказа: 2
Порядок очередей: 2
Работа завершена!
Заказ: 0 выполнено
Заказ: 1 выполнено
Заказ: 2 выполнено

Обратите внимание, как основной поток сообщает рабочему начать через сообщение, а рабочий сообщает о завершении обратно основному потоку через сообщение.


Улучшения, которые вы могли бы сделать:

  • order может вернуть Promise это выполняется, когда работник заканчивает свою работу.
  • Вы можете подождать, чтобы опубликовать "Работа завершена", пока все обещания заказа не будут выполнены.
  • Рабочий может публиковать промежуточные обновления своего прогресса обратно в главный поток.
  • Очевидно, что вы могли бы включить более значимую информацию в сообщения между рабочими потоками и основным потоком.

Идея веб-работника сделала свое дело, и я смог придумать эквивалентный скрипт node.js

const Worker = require('webworker-threads').Worker;
var myWorker = new Worker(function() {
  onmessage = function(event) {
    console.log("Received order " + event.data.orderNumber + " and it is being processed");
    for (var i = 0; i <= 100000000; i++); // processing time.
    postMessage("Order " + event.data.orderNumber + " has been successfully processed");
  }
});

for (var i = 0; i < 3; i++) {
  console.log("Taking order number: " + i);
  myWorker.postMessage({
    orderNumber: i
  });
  myWorker.onmessage = function(event) {
    console.log(event.data);
  }
}
console.log("Completed accepting orders!");

И вывод выглядит следующим образом:

Taking order number: 0
Taking order number: 1
Received order 0 and it is being processed
Taking order number: 2
Completed accepting orders!
Received order 1 and it is being processed
Received order 2 and it is being processed
Order 0 has been successfully processed
Order 1 has been successfully processed
Order 2 has been successfully processed
Другие вопросы по тегам