简体   繁体   English

Javascript与VBA的DoEvents有什么相似之处吗?

[英]Does Javascript have anything similar to VBA's DoEvents?

I have a long running for-loop in my code and I'd like to delay to loop to handle other tasks in the event queue (like a button press). 我的代码中有一个长时间运行for循环,我想延迟循环来处理事件队列中的其他任务(比如按下按钮)。 Does javascript or JQuery have anything that could help me? javascript或JQuery有什么可以帮助我吗? Basically I'm trying to do something similar to delaying loops like here ( https://support.microsoft.com/en-us/kb/118468 ). 基本上我正在尝试做类似延迟循环的事情( https://support.microsoft.com/en-us/kb/118468 )。

If your application really requires long-running JavaScript code, one of the best ways to deal with it is by using JavaScript web workers . 如果您的应用程序确实需要长时间运行的JavaScript代码,那么处理它的最佳方法之一就是使用JavaScript Web worker JavaScript code normally runs on the foreground thread, but by creating a web worker you can effectively keep a long-running process on a background thread, and your UI thread will be free to respond to user input. JavaScript代码通常在前台线程上运行,但是通过创建Web worker,您可以在后台线程上有效地保持长时间运行的进程,并且您的UI线程可以自由地响应用户输入。

As an example, you create a new worker like this: 例如,您创建一个像这样的新工作者:

var myWorker = new Worker("worker.js");

You can then post messages to it from the js in the main page like this: 然后,您可以从主页面中的js向其发布消息,如下所示:

myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');

And respond to the messages in worker.js like this: 并回复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);
}

You can use the setTimeout: 您可以使用setTimeout:

setTimeout(function() { }, 3600);

3600 it's the time in milliseconds: 3600是时间(以毫秒为单位):

http://www.w3schools.com/jsref/met_win_settimeout.asp http://www.w3schools.com/jsref/met_win_settimeout.asp

With the introduction of generators in ES6, you can write a helper method that uses yield to emulate DoEvents without much syntactic overhead: 通过在ES6中引入生成器,您可以编写一个帮助器方法,该方法使用yield来模拟DoEvents,而不会产生太多的语法开销:

doEventsOnYield(function*() {
    ... synchronous stuff ...

    yield;  // Pump the event loop. DoEvents() equivalent.

    ... synchronous stuff ...
});

Here's the helper method, which also exposes the completion/failure of the function as a Promise: 这是辅助方法,它还将函数的完成/失败暴露为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();
    });
}

Note that, at this time, you probably need to run this through an ES6-to-ES5 transpiler for it to run on common browsers. 请注意,此时,您可能需要通过ES6-to-ES5转换器运行它,以便在常见浏览器上运行。

There is no exact equivalent to DoEvents . 没有与DoEvents完全等效的东西。 Something close is using setTimeout for each iteration: 关闭的是每次迭代都使用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

However , that's rarely a good solution, and is almost never necessary in web applications. 但是 ,这很少是一个很好的解决方案,在Web应用程序中几乎不需要。 There might be an event you could use that you're missing. 您可能会遇到一个您遗失的事件。 What's your real problem? 你真正的问题是什么?

Here's a tested example of how to use Yield as a direct replacement for DoEvents. 以下是如何使用Yield作为DoEvents的直接替代品的测试示例。

(I've used Web Worker and it's great, but it's far removed from DoEvents and near-impossible to access global variables). (我使用过Web Worker,它很棒,但它远离DoEvents,几乎不可能访问全局变量)。 This has been formatted for ease of understanding and attempts to show how the extras required (to make the function handle yield) could be treated as an insertion within the original function. 这已经过格式化以便于理解,并试图显示所需的额外内容(使函数处理产量)可以被视为原始函数中的插入。 "yield" has all sorts of other features, but used thus, it is a near direct replacement for 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> 

..If you are new to all this, be aware that without the insertion and the yield keyword, you would simply wait 5 seconds while nothing happened and then the progress {div} would read "9" (because all the other changes to {div} were invisible). ..如果您对这一切都不熟悉,请注意,如果没有插入和yield关键字,您只需等待5秒而没有任何事情发生,然后进度{div}将显示为“9”(因为所有其他更改为{ div}是看不见的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM