【问题标题】:How to preserve setTimeout parameter value until execution?如何在执行之前保留 setTimeout 参数值?
【发布时间】:2013-12-03 17:01:58
【问题描述】:

我有一些代码在按键上执行,并在用户键入时将数据保存到数据库中。

我添加了一个 setTimeout 函数,它前面有一个 clearTimeout,所以用户输入的每个字符都不会发送 Ajax 请求来保存数据。

虽然 setTimeout 对一个输入字段非常有效,但如果用户决定快速切换输入字段(在 setTimeout 延迟结束之前),传递给 callSomeAjax 的参数会在函数执行之前发生变化。

正在发生的事情的简化版本...

var a = 1; //some user data

//function to call ajax script to save data to database
function callSomeAjax(a)
{
   console.log(a);
}

setTimeout(function(){callSomeAjax(a)},1000); //executes callSomeAjax after 1 second delay

a=3; //change user data before callSomeAjax executes

// Result of console.log is 3, not 1 like I want it to be...

Code on fiddle

有什么想法吗?

【问题讨论】:

  • 您是尝试为每个输入字段进行单独的 ajax 更新,还是 1 次 ajax 调用将整个表单保存到数据库?
  • 不要使用全局 setTimeout,只要在用户开始输入时创建一个,在用户输入的输入范围内?

标签: javascript settimeout


【解决方案1】:

较新的浏览器允许您将参数传递给setTimeout,并在回调中检索它。

setTimeout(function(a){
    return callSomeAjax(a);
}, 1000, a);

或者你可以将它绑定到函数

setTimeout(function(a){
    return callSomeAjax(a);
}.bind(null, a), 1000);

除此之外,您还需要在具有值的新范围内创建 setTimeout 回调。

function callbackWithValue(a) {
    return function() {
        return callSomeAjax(a);
    };
}

setTimeout(callbackWithValue(a), 1000);

或者,如果您已经拥有该功能,并且没有其他要传递的内容,那么您可以使其更通用...

function callbackWithValue(fn) {
    var args = [].slice.call(arguments, 1);
    return function() {
        return fn.apply(null, args);
    };
}

setTimeout(callbackWithValue(callSomeAjax, a), 1000);

最后一个是.bind() 函数的开始。它可以进一步扩展以允许绑定this 以及在绑定后传递的附加参数的串联。

【讨论】:

    【解决方案2】:

    问题是setTimeout 直到 1 秒后才运行传入的函数。 a 发生的事情发生了变化,所以当 callSomeAjax(a) 运行时,a 处于其新值。

    您需要在调用setTimeout 之前捕获(在闭包中)a 的值。

    var a = 1;
    
    function show(a) {
        console.log(a);
    }
    
    (function(a){
        setTimeout(function () {
            show(a)
        }, 1000);
    }(a));
    
    a = 3;
    

    演示:http://jsfiddle.net/U59Hv/2/

    【讨论】:

    • 此解决方案效果很好,但我想了解您在这里做什么。我得到了闭包的基本概念......闭包是函数内部的函数。内部或子函数可以访问父函数中的变量....但是当您将 (a) 放在 a = 3 之前的行的括号中时会发生什么?
    • 发生的事情是我正在创建一个函数function(a){},然后我立即调用它(function(a){}(a))。这会调用我的匿名函数并将a 作为参数传递。它被称为立即调用函数表达式 (IIFE)。这可能会有所帮助:en.wikipedia.org/wiki/Immediately-invoked_function_expression
    【解决方案3】:

    这很有效,也可以在循环中使用。

    var x = "OK";
    setTimeout(alertOK.bind(null,x), 3000);
    x = "Would be WRONG";
    console.log("before timeout:", x);
    
    function alertOK(x){
    	console.log("after timeout:",x);
    }
    这可能不是比公认的更好的答案,只是不同的想法。由于没有创建函数,因此它也可以在循环中使用。 在我看来,这种方式的代码更具可读性。

    【讨论】:

    • 您能否添加一些有关其工作原理以及为什么这比现有(和已接受)答案更好的信息?
    • @DaleMyers:它可能并不比现有的更好,只是另一种方法和更简单的代码,IMO。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 2015-10-21
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多