如何在“中运行javascript函数”;背景不冻结用户界面

如何在“中运行javascript函数”;背景不冻结用户界面,javascript,Javascript,我已经完成了一个HTML表单,它在许多不同的选项卡中有很多问题(来自数据库)。用户然后给出这些问题的答案。每次用户更改选项卡时,我的Javascript都会创建一个保存。问题是每次更改选项卡时,我都必须循环检查所有问题,每次都会将表单冻结大约5秒钟 我一直在寻找如何在后台运行save函数的答案。显然,没有真正的方法在后台运行某些东西,许多人建议使用setTimeout()例如这个 但这些例子都没有解释或考虑到这一点,即使我使用了setTimeout(saveFunction,2000)它不能解决

我已经完成了一个HTML表单,它在许多不同的选项卡中有很多问题(来自数据库)。用户然后给出这些问题的答案。每次用户更改选项卡时,我的Javascript都会创建一个保存。问题是每次更改选项卡时,我都必须循环检查所有问题,每次都会将表单冻结大约5秒钟

我一直在寻找如何在后台运行save函数的答案。显然,没有真正的方法在后台运行某些东西,许多人建议使用
setTimeout()例如这个

但这些例子都没有解释或考虑到这一点,即使我使用了
setTimeout(saveFunction,2000)它不能解决我的问题。在这种情况下,它只会延迟2秒

有什么办法可以解决这个问题吗?

你可以看一看,它们并没有得到广泛的支持

显然没有真正的方法在后台运行某些东西

有(但不是IE9和更早版本):

但我认为你试图在错误的层面上解决问题:1。在不到5秒的时间内,应该可以在批次中循环通过所有控件,并且2。当只有一个控件发生更改时,不必循环所有控件

我建议在尝试将处理过程转移到后台之前,先看看这些问题


例如,您可以拥有一个包含每个项目当前值的对象,然后让每个项目的UI在值更改时更新该对象。然后,您将拥有该对象中的所有值,而无需再次循环所有控件。

对于您描述的一个非常类似的问题,该库为我提供了很多帮助:


它基本上是一个基于WorkerQueue库的顺序后台队列。

只需创建一个隐藏按钮。将函数传递给其onclick事件。 无论何时您想要调用该函数(在后台),都可以调用按钮的click事件

<html>
<body>
    <button id="bgfoo" style="display:none;"></button>

    <script>
    function bgfoo()
    {
        var params = JSON.parse(event.target.innerHTML);
    }

    var params = {"params":"in JSON format"};
    $("#bgfoo").html(JSON.stringify(params));
    $("#bgfoo").click(bgfoo);
    $("#bgfoo").click(bgfoo);
    $("#bgfoo").click(bgfoo);
    </script>
</body>
</html>

函数bgfoo()
{
var params=JSON.parse(event.target.innerHTML);
}
var params={“params”:“JSON格式”};
$(“#bgfoo”).html(JSON.stringify(params));
$(“#bgfoo”)。点击(bgfoo);
$(“#bgfoo”)。点击(bgfoo);
$(“#bgfoo”)。点击(bgfoo);

这在后台工作:

setInterval(function(){ d=new Date();console.log(d.getTime()); }, 500);
你可以用。这里的一些旧答案说它们没有得到广泛的支持(我想在这些答案被写出来的时候它们没有),但是今天

要运行web worker,您需要创建内置
worker
类的实例。构造函数接受一个参数,该参数是包含要在后台运行的代码的javascript文件的URI。例如:

let worker = new Worker("/path/to/script.js");
Web workers受同源策略的约束,因此如果传递这样的路径,则目标脚本必须与调用它的页面位于同一域中

如果您不想为此创建新的Javascript文件,还可以使用数据URI:

let worker = new Worker(
    `data:text/javascript,
    //Enter Javascript code here
    `
);
由于同源策略,无法从数据URI发送AJAX请求,因此如果需要在web worker中发送AJAX请求,则必须使用单独的Javascript文件

您指定的代码(在单独的文件或数据URI中)将在您调用
Worker
构造函数时立即运行

不幸的是,web工作人员既不能访问外部Javascript变量、函数或类,也不能访问DOM,但您可以通过使用
postMessage
方法和
onmessage
事件来解决这个问题。在外部代码中,它们是worker对象的成员(
worker
,在上面的示例中),而在worker内部,它们是全局上下文的成员(因此可以使用
this
调用它们,或者像前面没有任何内容的那样调用它们)

postMessage
onmessage
都是双向工作的,因此当在外部代码中调用
worker.postMessage
时,在工作程序中调用
onmessage
,在工作程序中调用
postMessage
时,在外部代码中调用
worker.onmessage

let worker = new Worker(
    `data:text/javascript,
    function functionThatTakesLongTime(someArgument){
        //There are obviously faster ways to do this, I made this function slow on purpose just for the example.
        for(let i = 0; i < 1000000000; i++){
            someArgument++;
        }
        return someArgument;
    }
    onmessage = function(event){    //This will be called when worker.postMessage is called in the outside code.
        let foo = event.data;    //Get the argument that was passed from the outside code, in this case foo.
        let result = functionThatTakesLongTime(foo);    //Find the result. This will take long time but it doesn't matter since it's called in the worker.
        postMessage(result);    //Send the result to the outside code.
    };
    `
);

worker.onmessage = function(event){    //Get the result from the worker. This code will be called when postMessage is called in the worker.
    alert("The result is " + event.data);
}

worker.postMessage(foo);    //Send foo to the worker (here foo is just some variable that was defined somewhere previously).
postMessage
接受一个参数,该参数是您要传递的变量(但您可以通过传递数组来传递多个变量)。不幸的是,无法传递函数和DOM元素,当您尝试传递对象时,将只传递其属性,而不传递其方法

onmessage
接受一个参数,它是
MessageEvent
对象。
MessageEvent
对象有一个
data
属性,它包含使用
postMessage
的第一个参数发送的数据

下面是一个使用web workers的示例。在本例中,我们有一个函数,
functionthatakeslongtime
,它接受一个参数并根据该参数返回一个值,我们希望使用web workers在不冻结UI的情况下查找
函数thatakeslongtime(foo)
,其中
foo
是外部代码中的某个变量

let worker = new Worker(
    `data:text/javascript,
    function functionThatTakesLongTime(someArgument){
        //There are obviously faster ways to do this, I made this function slow on purpose just for the example.
        for(let i = 0; i < 1000000000; i++){
            someArgument++;
        }
        return someArgument;
    }
    onmessage = function(event){    //This will be called when worker.postMessage is called in the outside code.
        let foo = event.data;    //Get the argument that was passed from the outside code, in this case foo.
        let result = functionThatTakesLongTime(foo);    //Find the result. This will take long time but it doesn't matter since it's called in the worker.
        postMessage(result);    //Send the result to the outside code.
    };
    `
);

worker.onmessage = function(event){    //Get the result from the worker. This code will be called when postMessage is called in the worker.
    alert("The result is " + event.data);
}

worker.postMessage(foo);    //Send foo to the worker (here foo is just some variable that was defined somewhere previously).
let worker=新的worker(
`数据:text/javascript,
占用较长时间的函数(someArgument){
//显然有更快的方法可以做到这一点,我故意让这个函数变慢只是为了这个例子。
对于(设i=0;i<100000000;i++){
someArgument++;
}
返回一些参数;
}
onmessage=function(event){//在外部代码中调用worker.postMessage时将调用此函数。
让foo=event.data;//获取从外部代码传递的参数,在本例中为foo。
让result=functionThatTakesLongTime(foo);//查找结果。这将花费很长时间,但这并不重要,因为它是在worker中调用的。
postMessage(result);//将结果发送到外部代码