Узел: разрешить цикл событий в длинной задаче с возвратом

У меня есть функция, которая должна понравиться

    function longFunc(par1,par2)
    {
        var retVal = [], stopReq = false;
        function evtLs() { stopReq = true; }
        something.on("event",  evtLs);
        for(var i=0;i<possibleResults1.length;i++) { 
            if (isValid(possibleResults1[i])) 
                retVal.push(possibleResults1[i]); 
        }
        if (stopReq) return retVal;
        if (canAddResult2()) {
            for(var i=0;i<possibleResults2.length;i++) { 
                if (isValid(possibleResults2[i])) 
                    retVal.push(possibleResults2[i]); 
            }
            if (stopReq) return retVal;
        } else {
            for(var i=0;i<possibleResults3.length;i++) { 
                if (isValid(possibleResults3[i])) 
                    retVal.push(possibleResults3[i]); 
            }
            if (stopReq) return retVal;
        }
        something.removeListener("event", evtLs);
        return retVal;
    }

Моя проблема в том, что, не обращая внимания, событие никогда не генерируется, потому что процесс занят longFunc.

Как я могу преобразовать его, чтобы разрешить генерацию событий?

Вот проверяемый пример:

    var cancelled = false;

    setTimeout(() => cancelled = true,1000);
    function main()
    {
       var ret = []
       var totalStart =Date.now(); 
       for(var i=0;i<20;i++)
       {
          var v
          var start =  Date.now();
          while((Date.now()-start)<100)
          {
             v=Math.sqrt(Math.random());
          }
          ret.push(v);
          if (cancelled) break;
       }
       console.info("delta:"+(Date.now()-totalStart));
       return ret;
    }

    var r = main()
    console.info(r.length)

Я ожидаю эту остановку после 1000, но вместо этого останавливаюсь после 2000.

Что должен делать общий код?

Jonas Wilms 07.05.2019 10:50

если все эти do thinks and can retVal.push(); синхронны, то evtLs нельзя вызывать, пока они все равно не закончатся - вы, наверное, это знаете, но без малейшего представления о том, что "думает" вы "делаете", ответ - кокос

Jaromanda X 07.05.2019 10:51

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

Perry 07.05.2019 10:54

не зная подробностей того, что вы «думаете», что вы «делаете» в этих циклах, ответ по-прежнему остается кокосовым.

Jaromanda X 07.05.2019 10:55

Я не думаю, что код внутри "думает и может retVal.push();" здесь все равно важно, это как: for(var i=0;i<possibleResults.length;i++) { if (isValid(possibleResults[i])) retVal.push(possibleResults[i]); }

Perry 07.05.2019 10:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
5
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В JavaScript есть принцип, который в других языках часто называют кооперативный параллелизм: ваш код будет работать синхронно и без прерываний, если он явно не планирует прерывание. В вашем случае код будет работать без перерыва, любое инициированное событие будет выполнено после завершения этого кода. Теперь, чтобы поддерживать прерывание, вам нужно иногда останавливать выполнение в середине, функции async действительно полезны для этого:

  function interruptable(task) {
     let cancelled = false;
     const tick = () => new Promise(res => setTimeout(res));

     const done = task(() => cancelled ? Promise.reject() : tick()).catch(e => e);


      return { done, cancel() { cancelled = true } };
  }



  function taskWithInterrupt() {
     const result = [];

     const { cancel, done } = interruptable(async function(tick) { // we enter the async execution flow
        doTaskA();
        await tick(); // allow for interrupts here
        doTaskB();
        await tick();
      });

      someKillSwitch.on("event", cancel);

       return done.then(() => result);
   }

Эта реализация выглядит блестяще. Я ожидал, что в nodejs есть что-то встроенное для этого. Мы уверены, что нет?

Cristian Traìna 07.05.2019 11:15
Ответ принят как подходящий

После некоторых тестов и поиска помощи в другом вопросе Node.js: разрешить обновление процесса во время цикла Я решил свою проблему с помощью setImmediate следующим образом:

var cancelled = false;

setTimeout(() => { console.info("cancel"); cancelled = true},1000);

main = new Promise((resolve,reject)=> {
   var ret = []
   function Step(i) {
      try {
         console.info("step "+i);
         var start =  Date.now();
         while((Date.now()-start)<100)
         {
            v=Math.sqrt(Math.random());
         }
         ret.push(v);
         if (i==20 || cancelled)
         {
            resolve(ret);
            return
         }
         setImmediate(Step.bind(null,i+1))            
      } catch (error) {
         reject(error)
      }
   }
   Step(0);
});

var totalStart =Date.now(); 
main.then((r)=>{
   console.info("delta:"+(Date.now()-totalStart));
   console.info(r.length)   
})

Таким образом, вывод:

step 0
step 1
step 2
step 3
step 4
step 5
step 6
step 7
step 8
step 9
cancel
step 10
delta:1004
11

поэтому он останавливается через 1000 мс, как и ожидалось.

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