У меня есть функция, которая должна понравиться
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.
если все эти do thinks and can retVal.push(); синхронны, то evtLs нельзя вызывать, пока они все равно не закончатся - вы, наверное, это знаете, но без малейшего представления о том, что "думает" вы "делаете", ответ - кокос
Это веб-сервис, на самом деле longfunc сам является прослушивателем событий, но может случиться так, что клиент вызовет другой веб-метод, чтобы остановить последний запрос.
не зная подробностей того, что вы «думаете», что вы «делаете» в этих циклах, ответ по-прежнему остается кокосовым.
Я не думаю, что код внутри "думает и может retVal.push();" здесь все равно важно, это как: for(var i=0;i<possibleResults.length;i++) { if (isValid(possibleResults[i])) retVal.push(possibleResults[i]); }



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В 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 есть что-то встроенное для этого. Мы уверены, что нет?
После некоторых тестов и поиска помощи в другом вопросе 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 мс, как и ожидалось.
Что должен делать общий код?