【问题标题】:How to add a kill method to an existing jQuery plugin?如何向现有的 jQuery 插件添加 kill 方法?
【发布时间】:2012-04-13 01:25:58
【问题描述】:

我正在使用发布在以下位置的插件代码:

jQuery Tips and Tricks

...本质上是一个异步定时器循环:

jQuery.forEach = function (in_array, in_pause_ms, in_callback)
{
    if (!in_array.length) return; // make sure array was sent

    var i = 0; // starting index

    bgEach(); // call the function

    function bgEach()
    {
        if (in_callback.call(in_array[i], i, in_array[i]) !== false)
        {
            i++; // move to next item

            if (i < in_array.length) setTimeout(bgEach, in_pause_ms);
        }
    }

    return in_array; // returns array
};


jQuery.fn.forEach = function (in_callback, in_optional_pause_ms)
{
    if (!in_optional_pause_ms) in_optional_pause_ms = 10; // default

    return jQuery.forEach(this, in_optional_pause_ms, in_callback); // run it
};

在这个伟大社区的帮助下,我了解到,如果我“回归真实”;或“返回错误;”它与继续循环的下一次迭代具有相同的效果。

我想做的也是以编程方式完全终止(销毁)$.forEach 循环调用,不允许剩余的迭代运行。

如何向此插件添加方法以允许我终止对插件的特定调用,同时不影响同时运行的其他调用?

我考虑过将调用分配给这样的变量:

var foo = $.forEach(json, 1000, function(idx,item) { /* do stuff */ });

...稍后引用特定实例而不影响其他实例,但是如何添加 kill 方法并在 foo 上调用它?我需要与 ajax 调用一起使用的 foo.abort() 等效项。

可以吗?如果有,怎么做?

【问题讨论】:

    标签: javascript jquery jquery-plugins loops settimeout


    【解决方案1】:

    这实际上只是示例代码,因此存在一些问题。

    您可以通过简单地向 in_array 对象添加一个 expando 属性来缓解这种情况:

    jQuery.forEach = function (in_array, in_pause_ms, in_callback)
    {
        // Note, you should use $.isArray(), which is smarter than checking length.
        if (!$.isArray(in_array)) return false;
        in_array.valid = true;
        var i = 0; // starting index
        function bgEach()
        {
            if (!in_array.valid) return;
            if (in_callback.call(in_array[i], i, in_array[i]) !== false)
            {
                i++; // move to next item
    
                if (i < in_array.length) setTimeout(bgEach, in_pause_ms);
            }
        }
    
        // I moved this because you were calling it before it was defined.
        bgEach(); // call the function
        return in_array; // returns array
    };
    

    由于您从方法中获取原始数组对象,因此您可以在完成后将对象的“有效”属性设置为 false:

    var foo = $.forEach(json, 1000, function(idx,item) { /* do stuff */ });
    foo.valid = false;
    

    由于valid 属性取消了setTimeout 递归,这将有效地终止循环。

    请注意,这种代码有些危险。你会遇到竞争条件等等,但是当你开始在 JS 中执行伪线程和异步代码时就会发生这种情况。

    【讨论】:

    • @John Green - 你能解释一下比赛条件的评论吗?我实现了这个来避免与 $.each 或 for 循环相关的 UI 锁定,但想知道使用这种方法有什么危险。非常感谢。
    • 嗯,您正在运行一个项目队列,并且一次只调用一个。如果您必须通过数组返回某些其他功能,您可能需要在一个地方切换状态的情况下结束,但它已经排队等待在异步数组中以另一种方式切换。通常,您的首要任务应该是优化您的查询和关闭,尽管您总是可能需要这样的队列。不过,根据我的经验,我发现 99% 的人希望实现类似的东西,实际上应该优化他们的代码。
    【解决方案2】:

    您可以将计时器传递给回调并更改

    if (i < in_array.length) setTimeout(bgEach, in_pause_ms);
    

    if (i == in_array.length) clearTimeout(timeout);
    

    这将保证它只会循环尽可能多的项目。

    这里是 jQuery forEach:

    jQuery.forEach = function (in_array, in_pause_ms, in_callback)
    {
        if (!in_array.length) return; // make sure array was sent
    
        var i = 0; // starting index
    
        bgEach(); // call the function
    
        function bgEach(){
            var timeout;
            if (in_callback.call(in_array[i], i, in_array[i], timeout = setTimeout(bgEach, in_pause_ms)) !== false)
            {
                i++; // move to next item
                // if end of array, stop iterating
                if (i == in_array.length) clearTimeout(timeout);
            }
        }
    
        return in_array; // returns array
    };
    

    如果计时器满足某些条件,您可以使用它来清除计时器,从而结束循环。示例:

    $.forEach([1,2,3], 1000, function(idx, item, timer) {
      if(item == 2) {
        clearTimeout(timer);
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多