0

我正在做一个客户端模拟,它可以实时进行后台计算和视图刷新。但是,由于模拟始终是实时的,CPU 最终会在用户输入和编辑过程中进行大量不必要的工作。

我想要实现的是一种杀死用户事件的整个序列的方法。

主应用程序中的预期用法:

var sequence =  new Sequence(heavyFunc1, heavyFunc2, updateDom);
document.addEventListener("click", sequence.stop)
sequence.run() //all the heavy computation runs until told to stop

网络工作者的预期用法:

var sequence =  new Sequence(heavyFunc1, heavyFunc2, self.postmessage);
self.onmessage = function(e) {
    if (e.data === 'stop') msg = sequence.stop;
    else msg = sequence.run(e.data); //resets and restarts
};

我环顾四周,可以想到以下工具和模式:

setTimout(fcn,0) || setImmediate(fcn) shim :将主脚本和工作线程中的序列内的各个步骤包装起来,setTimeout(fcn,0)以在序列结束之前处理新事件。

killFlag = false;
window.addEventListener('keypress', function() {killFlag = true});

//this exampe works only with setTimeout, fails with setImmediate lib
var interruptibleSequence = function(tasks) {
  var iterate = function() {
    if (killFlag || !tasks.length) return;
    tasks.shift()();
    if (tasks.length) window.setTimeout(iterate,0);
  };
  iterate();
};

此示例与 setTimeout 一起使用,但在按键事件总是最后出现的 setImmediate 中失败。

debounce :这是典型的答案,似乎不适用于我的情况。延迟和批处理用户输入会以更长的处理时间为代价部分降低处理强度。

Promises:我已经在对工作结果使用 Promise,并且可以在步骤之间引入额外的 Promise 来中断序列并处理新事件。我已经尝试(但失败了)使用标志检查或Promise.race.

杀旗

killFlag = false;
window.addEventListener('keypress', function() {killFlag = true});

//does not work. promises get priority and event is only triggered last
var interruptibleSequence = function(tasks) {
  var seq = Promise.resolve();
    tasks.forEach(function(task){
      seq = seq.then(function() {
        if (killFlag) return;
        else task();
    });
  });
};

Promise.race

var killTrigger;
var killPromise = new Promise(function(res,rej){killTrigger = rej});
window.addEventListener('keypress', killTrigger());

//does not work. promises get priority and event is only triggered last
var raceToFailure = function(tasks) { 
  var seq = Promise.resolve();
  tasks.forEach(function(task){
    seq = Promise.race([seq.then(task),killPromise]);
  });
};

问题 在事件中终止序列的推荐模式是什么?

4

1 回答 1

0

简而言之: 调用堆栈>> Promise >>消息队列(事件和 setTimeout)

事实证明,这个问题的表述很糟糕,而且对于特定的用例来说太具体了。一般来说,对于立即返回的同步函数,将它们包装在一系列 Promise 中确实会将控制权移交给下一个函数,但仍然优先于消息队列中的事件,即使是在创建 Promise 之前触发的事件。接受的答案并不总是有效。

在下面的代码片段中,EventPromiseSync调用最终以SyncPromiseEvent顺序执行。(需要原生 Promise)

因此,让事件中断繁重计算的唯一方法是使用 setTimeout 暂存繁重的同步函数。

//prep
function log(m) {document.getElementsByTagName('pre')[0].innerHTML += m+'<br>'}
function syncDelay(ms) {
    for (var tgt=Date.now()+ms; Date.now()<tgt;) Math.random();
}

function async1() {syncDelay(100); log('1. async1')}
window.addEventListener('message', function(e){log(e.data)});
function syncPr1() {syncDelay(100); log('3. syncPromise1')}
function syncPr2() {syncDelay(100); log('4. syncPromise2')}
function syncPr3() {syncDelay(100); log('5. syncPromise3')}


//sequence
setTimeout(async1,0);
window.postMessage('2. events get done last', '*');

Promise.resolve()
.then(syncPr1)
.then(syncPr2)
.then(syncPr3)
.catch(function(e){console.log(e)});

log('6. sync items get executed before next promise call');
<pre></pre>

于 2015-01-29T03:39:51.653 回答