本文介绍了模式的浏览器的事件中断繁重的计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个客户端仿真,做动态背景计算和视图刷新。但是,由于仿真是永远活时,CPU最终在激烈的用户输入和编辑做了很多不必要的工作。

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

在主要应用预期用法:

 无功序列=新序列(heavyFunc1,heavyFunc2,updateDom);
document.addEventListener(点击,sequence.stop)
sequence.run()//所有繁重的计算运行,直到被告知停止

在一个网络工作者的预期用法:

 无功序列=新序列(heavyFunc1,heavyFunc2,self.postmessage);
self.onmessage =功能(E){
    如果(e.data ==='一站式')味精= sequence.stop;
    否则味精= sequence.run(e.data); //重新设置并重新启动
};

我环顾四周,并能想到的下列工具和模式:

setTimout(FCN,0)|| setImmediate(FCN)垫片:裹在两个主脚本和工人序列内的各个步骤的setTimeout(FCN,0)年底前processe新事件序列

  killFlag = FALSE;
window.addEventListener(键preSS',函数(){killFlag =真});//这个exampe仅适用于setTimeout的,失败setImmediate LIB
VAR interruptibleSequence =功能(任务){
  VAR迭代=功能(){
    如果(killFlag || tasks.length!)回报;
    tasks.shift()();
    如果(tasks.length)window.setTimeout(迭代,0);
  };
  迭代();
};

此例如使用setTimeout的工作,但与setImmediate失败了其中关键的preSS事件总是​​排在最后。

防抖动:这是一个似乎并不在我的情况,应用典型的回答。延迟和配料用户输入将部分减少加工强度在较长处理时间为代价的。

承诺:我已经使用的承诺为职工后果,并可能引入措施来中断的顺序和处理新的事件之间的附加承诺。我已经使用或者标志支票或试图(和失败的) Promise.race

使用的杀标志

  killFlag = FALSE;
window.addEventListener(键preSS',函数(){killFlag =真});//不起作用。承诺获得优先权和事件时,才会触发最后
VAR interruptibleSequence =功能(任务){
  变种SEQ = Promise.resolve();
    tasks.forEach(函数(任务){
      SEQ = seq.then(函数(){
        如果(killFlag)回报;
        别的任务();
    });
  });
};

使用的 Promise.race

  VAR killTrigger;
VAR killPromise =新的承诺(功能(RES,REJ){killTrigger = REJ});
window.addEventListener('键preSS',killTrigger());//不起作用。承诺获得优先权和事件时,才会触发最后
VAR raceToFailure =功能(任务){
  变种SEQ = Promise.resolve();
  tasks.forEach(函数(任务){
    SEQ = Promise.race([seq.then(任务),killPromise]);
  });
};


什么是推荐的方式杀事件的顺序?


解决方案

活动简介: 调用堆栈的>>的无极的>> 消息队列(事件&安培; setTimeout的)

原来,问题是严重的制定和过于具体到特定的用例。一般来说,对于立即返回,在所应许的序列包裹它们的同步功能的确交出控制权到下一个功能,但仍然需要precedence了在消息队列中的事件,甚至那些承诺之前触发创建。接受答案并不总是奏效。

在下面的代码片段中,事件无极同步的在正在执行的呼叫结束了的同步的,无极事件的顺序。 (需要本地的承诺)

因此​​,只有这样,才能让事件中断了沉重的计算是用setTimeout的阶段性重同步功能。

\r
\r

// preP\r
功能日志(M){document.getElementsByTagName('pre')[0] .innerHTML + = M +'< BR>'}\r
功能SYNCDELAY(毫秒){\r
    对于(VAR TGT = Date.now()+ MS; Date.now()< TGT)的Math.random();\r
}\r
\r
功能async1(){SYNCDELAY(100);日志('1。async1')}\r
window.addEventListener(信息,功能(E){日志(e.data)});\r
功能syncPr1(){SYNCDELAY(100);日志('3。syncPromise1')}\r
功能syncPr2(){SYNCDELAY(100);日志('4。syncPromise2')}\r
功能syncPr3(){SYNCDELAY(100);日志('5。syncPromise3')}\r
\r
\r
//序列\r
的setTimeout(async1,0);\r
window.postMessage('2事件得到完成最后一次。','*');\r
\r
Promise.resolve()\r
。然后(syncPr1)\r
。然后(syncPr2)\r
。然后(syncPr3)\r
.catch(函数(五){执行console.log(五)});\r
\r
LOG(6同步项目将在下一个承诺调用之前执行');

\r

< pre>< / pre>

\r

\r
\r

I'm working on a client side simulation that does on the fly background computation and view refresh. However, because the simulation is always live, the CPU ends up doing a lot of unnecessary work during intense user inputs and edits.

What I want to achieve is a way to kill the whole sequence on user event.

anticipated usage in the main app:

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

anticipated usage in a web worker:

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
};

I've looked around and can think of the following tools and patterns:

setTimout(fcn,0) || setImmediate(fcn) shim : Wrap the individual steps setTimeout(fcn,0) inside the sequences in both the main script and worker to processe new events before the end of the sequence.

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();
};

This example worked with setTimeout but failed with setImmediate where the keypress event always came in last.

debounce : This is the typical answer that does not seem to apply in my case. Delaying and batching user inputs would partly reduce the processing intensity at the expense of longer processing time.

Promises : I'm already using promises for worker results and could introduce additional promises between steps to interrupt the sequence and process new events. I've tried (and failed) using either flag checks or Promise.race.

With kill flag

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();
    });
  });
};

With 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]);
  });
};

QuestionWhat would be the recommended pattern to kill a sequence on event?

解决方案

In Short: Call Stack >> Promise >> Message Queue (events & setTimeout)

Turns out the question was badly formulated and too specific to a particular use case. In general, for sync functions that return immediately, wrapping them in a sequence of promise does hand over control to the next function but still take precedence over events in the message queue, even those fired before the Promises were created. The accepted answer does not always work.

In the snippet below, the Event, Promise, Sync calls end up being executed in the Sync, Promise, Event order. (native Promises required)

The only way therefore to let events interrupt a heavy computation is to stage the heavy sync functions with 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>

这篇关于模式的浏览器的事件中断繁重的计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 09:57