【问题标题】:How to Break out of Jquery's Each Loop WITH PROMISE如何用 PROMISE 打破 Jquery 的每个循环
【发布时间】:2013-12-17 17:27:08
【问题描述】:

我的问题是:How to break out of jQuery each Loop

我需要从 jquery $.each() 中退出,但在这种情况下我不能返回 FALSE,因为退出条件正在触发一个将解决延迟的函数。所以我需要退出每一个,但要有一个承诺。

function KillLayer(id) {
    var defer = $.Deferred();
    $.each(vm.get("DeviceData"), function (idx, item) {
        if (item.Type == id) {
            vm.DeviceData.splice(idx, 1); // remove the item from the list
            removeLayer(defer, id)  // delete it from the PouchDB (IDB) database (async)
            return defer.promise();
        }
    });
    defer.resolve(); // layer was not found, so just resolve & return
    return defer.promise();
}

【问题讨论】:

    标签: jquery asynchronous jquery-deferred


    【解决方案1】:

    正如您所发现的,您不能在其 each() 循环内从 KillLayer() 返回,因为该上下文中的 return 语句具有不同的含义。

    这里有几种不同的方法:

    1:使用布尔标志来表示是否发生了删除,并相应地处理 Deferred。

    function KillLayer(id) {
        var defer = $.Deferred(), deleted = false;
        $.each(vm.get("DeviceData"), function (idx, item) {
            if (item.Type == id) {
                vm.DeviceData.splice(idx, 1); // remove the item from the list
                removeLayer(defer, id);  // delete it from the PouchDB (IDB) database (async)
                deleted = true;
                return false;//break from each() loop
            }
        });
        return deleted ? defer.promise() : defer().resolve().promise();//return either a promise of deletion or a ready-resolved promise.
    }
    

    2:(如果你可以控制removeLayer())安排removeLayer() 生成并返回它自己的promise,而不是传入一个Deferred。这将允许您将KillLayer() 简化如下:

    function KillLayer(id) {
        var deletionPromise;
        $.each(vm.get("DeviceData"), function (idx, item) {
            if (item.Type == id) {
                vm.DeviceData.splice(idx, 1); // remove the item from the list
                deletionPromise = removeLayer(id);  // delete it from the PouchDB (IDB) database (async), and receive back a promise
                return false;//break from each() loop
            }
        });
        return deletionPromise || $.Deferred().resolve().promise(); //return either a promise of deletion from the DB, or a ready-resolved promise
    }
    

    虽然只有一条线不同,但我认为第二种方法更清晰。由于removeLayer() 执行异步活动,它应该真正返回它自己的promise,而不是依赖传递给它的Deferred。

    【讨论】:

    • 我正在使用解决方案#1(实际上,我昨晚想通了,当我测试它并去发布它时,我看到了你的答案!
    【解决方案2】:

    像这样试试。

    objDP = null;  // To get Deferred’s Promise object.
    
    $.each(vm.get("DeviceData"), function (idx, item) {
        if (item.Type == id) {
            vm.DeviceData.splice(idx, 1); // remove the item from the list
            removeLayer(defer, id)  // delete it from the PouchDB (IDB) database (async)
            objDP = defer.promise();
            return false;
        }
    });
    

    【讨论】:

    • 您应该在每个循环的开头添加对 objDp 的空检查,以防止以下迭代执行某些操作。
    • 但是由于return false,下面的迭代将无法运行,如果我错了,请纠正我。
    • 返回在每次迭代运行的委托函数中,它从该函数返回,而不是从循环中返回。
    • 我希望有更干净的东西。现在,KillLayer(id) 是一个简单的函数,它返回我可以何时或完成的承诺。我真的不想要一个需要结合使用的全局 objDP 变量。注意:现在我收到一个控制台错误,即 item.TYPE 未定义,但代码确实运行完成。
    【解决方案3】:

    这不会从每个循环中中断,但它会使以下迭代什么都不做:

    function KillLayer(id) {
        var defer = $.Deferred();
        var result = null;
        $.each(vm.get("DeviceData"), function (idx, item) {
            if (!result && item.Type == id) {
                vm.DeviceData.splice(idx, 1); // remove the item from the list
                removeLayer(defer, id)  // delete it from the PouchDB (IDB) database (async)
                result = defer.promise();
            }
        });
        return result || defer.resolve();
    }
    

    【讨论】:

    • 我看到来自 Chrome 的控制台日志错误说 item.Type 未定义。我认为这个解决方案会有同样的问题。 (是的,不是致命的,但我不希望出现错误)。
    • 我想知道迭代器委托为什么有两个参数而不是一个。我很确定每个人只将当前项目从迭代传递给委托。
    【解决方案4】:

    我独立提出了 Beetroots 的答案 #1。首先,我意识到循环通过 $each() 并从您正在循环的 javascript 数组中删除项目是错误的好方法。我真的应该这样做:

    $.each(clone(vm.get("DeviceData")), function (idx, item)` {
    

    其中克隆函数定义为:

    function clone(obj) {
        return jQuery.extend({}, obj);
    }
    
    function deepClone(obj) {
        return jQuery.extend(true, {}, obj);
    }
    

    但就我而言,我不需要额外的保护,所以我只是更新了我的解决方案,如下所示:

    function KillLayer(id) {
        var defer = $.Deferred();
        var found = false;
        $.each(vm.get("DeviceData"), function (idx, item) {
            if (item.Type == id) {
                vm.DeviceData.splice(idx, 1);
                Compare();
                dbManifest.LayerInfo = vm.DeviceData.toJSON();
                removeLayer(defer, id)
                found = true;
                return false;
            }
        });
        if (!found) defer.resolve(); // layer was not found, so just resolve & return
        return defer.promise();
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-19
      • 2014-02-06
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2021-08-12
      相关资源
      最近更新 更多