Как запустить разблокирующую фоновую задачу в клиенте Meteor/JavaScript?

Я хотел бы запустить задачу на клиенте Meteor, который требует ресурсов в фоновом режиме, и в то же время поддерживать интерфейс отзывчивым для пользователя. Задача выполняет некоторые математические операции (например, поиск простых чисел, как описано здесь: /questions/35067301/generatsiya-sluchajnogo-bolshogo-prostogo-chisla-s-pomoschyu-forge-ili-drugogo-podhoda-javascript/35067316#35067316).

Я пытался следовать советам с /questions/32619233/fonovyie-zadachi-v-meteore/32619238#32619238 но все равно интерфейс всегда "зависает", пока задача не будет выполнена.

setTimeout, setInterval и те пакеты, как в моем текущем подходе, также не помогли:

var taskQueue = new PowerQueue();
taskQueue.add(function(done) {
    doSomeMath();
    // It's still blocking/freezing the interface here until done() is reached
    done();
});

Могу ли я сделать что-то, чтобы сделать интерфейс отзывчивым во время работы doSomeMath(), или я делаю что-то не так (также не похоже, что в PowerQueue можно многое сделать неправильно)?

1 ответ

Решение

Библиотеки JavaScript, которые решают проблему асинхронной очереди, предполагают, что задачи, стоящие в очереди, выполняются в параллельной, но однопоточной среде, такой как node.js или ваш браузер. Однако в вашем случае вам нужно больше, чем просто параллелизм - вам нужно многопоточное выполнение, чтобы вывести ваши ресурсоемкие вычисления из потока пользовательского интерфейса. Это может быть достигнуто с веб-работниками. Обратите внимание, что веб-работники поддерживаются только в современных браузерах, поэтому продолжайте читать, если вас не интересует IE9.

Приведенной выше статьи должно быть достаточно, чтобы начать работу, однако стоит упомянуть, что рабочий скрипт нужно будет хранить за пределами дерева приложений, чтобы он не связывался. Самый простой способ сделать это - поместить его внутрь public каталог.

Вот быстрый пример, где мой работник вычисляет последовательность Фибоначчи (неэффективно):

общественные /fib.js

var fib = function(n) {
  if (n < 2) {
    return 1;
  } else {
    return fib(n - 2) + fib(n - 1);
  }
};

self.addEventListener('message', (function(e) {
  var n = e.data;
  var result = fib(n);
  self.postMessage(result);
  self.close();
}), false);

клиент /app.js

Meteor.startup(function () {
  var worker = new Worker('/fib.js');
  worker.postMessage(40);
  worker.addEventListener('message', function(e) {
    console.log(e.data);
  }, false);
});

Когда клиент запускается, он загружает работника и просит его вычислить 40-е число в последовательности. Это займет несколько секунд, но ваш пользовательский интерфейс должен оставаться отзывчивым. После того, как значение возвращено, оно должно напечатать 165580141 на консоль.

Другие вопросы по тегам