[英]Does Javascript have anything similar to VBA's DoEvents?
我的代碼中有一個長時間運行for循環,我想延遲循環來處理事件隊列中的其他任務(比如按下按鈕)。 javascript或JQuery有什么可以幫助我嗎? 基本上我正在嘗試做類似延遲循環的事情( https://support.microsoft.com/en-us/kb/118468 )。
如果您的應用程序確實需要長時間運行的JavaScript代碼,那么處理它的最佳方法之一就是使用JavaScript Web worker 。 JavaScript代碼通常在前台線程上運行,但是通過創建Web worker,您可以在后台線程上有效地保持長時間運行的進程,並且您的UI線程可以自由地響應用戶輸入。
例如,您創建一個像這樣的新工作者:
var myWorker = new Worker("worker.js");
然后,您可以從主頁面中的js向其發布消息,如下所示:
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
並回復worker.js
的消息,如下所示:
onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}
您可以使用setTimeout:
setTimeout(function() { }, 3600);
3600是時間(以毫秒為單位):
通過在ES6中引入生成器,您可以編寫一個幫助器方法,該方法使用yield
來模擬DoEvents,而不會產生太多的語法開銷:
doEventsOnYield(function*() {
... synchronous stuff ...
yield; // Pump the event loop. DoEvents() equivalent.
... synchronous stuff ...
});
這是輔助方法,它還將函數的完成/失敗暴露為Promise:
function doEventsOnYield(generator) {
return new Promise((resolve, reject) => {
let g = generator();
let advance = () => {
try {
let r = g.next();
if (r.done) resolve();
} catch (ex) {
reject(ex);
}
setTimeout(advance, 0);
};
advance();
});
}
請注意,此時,您可能需要通過ES6-to-ES5轉換器運行它,以便在常見瀏覽器上運行。
沒有與DoEvents
完全等效的東西。 關閉的是每次迭代都使用setTimeout
:
(function next(i) {
// exit condition
if (i >= 10) {
return;
}
// body of the for loop goes here
// queue up the next iteration
setTimeout(function () {
// increment
next(i + 1);
}, 0);
})(0); // initial value of i
但是 ,這很少是一個很好的解決方案,在Web應用程序中幾乎不需要。 您可能會遇到一個您遺失的事件。 你真正的問題是什么?
以下是如何使用Yield作為DoEvents的直接替代品的測試示例。
(我使用過Web Worker,它很棒,但它遠離DoEvents,幾乎不可能訪問全局變量)。 這已經過格式化以便於理解,並試圖顯示所需的額外內容(使函數處理產量)可以被視為原始函數中的插入。 “yield”具有各種其他功能,但因此使用它,它幾乎是DoEvents的直接替代品。
//'Replace DoEvents with Yield ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield ) var misc = 0; //'sample external var function myfunction() { //'This is the beginning of your original function which is effectively replaced by a handler inserted as follows.. //'-----------------------------------Insert Handler.. var obj = myfuncGen.next(); //'start it if (obj.done == false) { setTimeout(myfunction, 150); //'adjust for the amount of time you wish to yield (depends how much screen drawing is required or etc) } } var myfuncGen = myfuncSurrogate(); //'creates a "Generator" out of next. function* myfuncSurrogate() { //'This the original function repackaged! Note asterisk. //'-------------------------------------End Insert var ms; //...your original function continues here.... for (var i = 1; i <= 9; i++) { //'sample 9x loop ms = new Date().getTime(); while (new Date().getTime() < ms + 500); //'PAUSE (get time & wait 500ms) as an example of being busy misc++; //'example manipulating an external var outputdiv.innerHTML = "Output Div<br>demonstrating progress.. " + misc; yield; //'replacement for your doevents, all internal stack state and variables effectively hibernate. } console.log("done"); } myfunction(); //'and start by calling here. Note that you can use "return" to return a value except by call backs.
<div id='outputdiv' align='center'></div>
..如果您對這一切都不熟悉,請注意,如果沒有插入和yield關鍵字,您只需等待5秒而沒有任何事情發生,然后進度{div}將顯示為“9”(因為所有其他更改為{ div}是看不見的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.