【问题标题】:Cannot break recursion with $.Deffered() object and $.then()无法使用 $.Deferred() 对象和 $.then() 中断递归
【发布时间】:2014-05-25 22:40:00
【问题描述】:

我必须搜索可能有数十万行的单词索引表。我可以通过将文档列表传递给搜索来限制我的搜索。在许多文档中搜索单词的请求返回非常缓慢。所以...为了改善用户体验,我们将请求分成几组文档。因此,如果用户要求搜索 90 个文档,并且块大小是每个查询 10 个文档,那么我们发送 90 / 10 = 9 个独立的 $.ajax() 调用。我们希望结果按照发送的顺序出现。

我们实现了这个递归:

var SearchFunction = function () {
   $.ajax(/* ... */);
   }

var RecursiveSearch = function () {
   var deferred = $.Deferred();
   if (arrTransSearch.length > 0) {
      deferred = SearchDocuments(arrTransSearch.shift());
   }
   else {
      deferred.reject();
   }

   return deferred.promise().then(RecursiveSearch);
}

if (arrTransSearch.length > 1) {
   RecursiveSearch().fail(SomeFunction);
}

var SomeFunction = function () {
   alert("Failed. Yes!");
}

当我调试代码时,它似乎deferred.reject() 不会改变deferred.promise() 的状态。也就是当下一行

return deferred.promise().then(RecursiveSearch)

被执行,它只是循环回到递归函数中,而不是退出递归并陷入

RecursiveSearch().fail(SomeFunction);

重要提示:

我正在使用 jQuery-1.7.1。我在JSFiddle 中运行了类似的递归(谢谢Beeetroot-Beetroot),它在 jQuery-1.7.2 上失败,而在 jQuery-2.1.0 上它运行没有问题.

知道如何让递归在 jQuery-1.7.1 中工作吗?

【问题讨论】:

    标签: javascript jquery recursion jquery-deferred jquery-1.7


    【解决方案1】:

    here 在“The Collection Kerfuffle”标题下提供了部分覆盖您正在寻找的内容的模式。实际上,您需要的远不止这些,因为您希望以块(组)的形式处理您的文档引用列表。

    代码将是这样的:

    $(function() {
    
        //General ajax options for searching a document group
        var ajaxOptions = {
            url: '...',
            type: 'POST',
            //data: ... //added dynamically 
            dataType: 'JSON',
            // etc.
        };
    
        //
        function searchDocumentsInGroups(arr, n) {
            //Pre-process arr to create an array of arrays, where each inner array is a group of document references
            var groups = [];
            $.each(arr, function (i) {
                if (!(i % n)) groups.push(arr.slice(i, i + n));
            });
    
            //Ajax serializer (from the Collection Kerfuffle reference)
            return groups.reduce(function (promise, group) {
                return promise.then(function () {
                    return $.ajax($.extend({}, ajaxOptions, {
                        data: JSON.stringify(group);//or whatever, compatible with the server-side script
                    })).then(function (groupResults) {
                        //display groupResults here
                    });
                });
            }, $.when(0));
        }
    
        // data
        var myDocumentArray = [ 'doc1', 'doc2', 'doc3', 'doc4', 'etc.' ], //Your array of 90 document references.
            groupSize = 10; //Number of documents per "chunk".
    
        // Event handler to kick off the process.
        $("#searchDocuments").on('click', function () {
            // display "in progress" message or spinner here
            searchDocumentsInGroups(myDocumentArray, groupSize).then(function () {
                // display "complete" message or hide spinner here
            });
        });
    });
    

    您还需要 Array.prototype.reduce 的 Polyfill,因为 .reduce 依赖于上述内容,而旧版浏览器(ECMAScript5 之前)没有。

    if ( 'function' !== typeof Array.prototype.reduce ) {
      Array.prototype.reduce = function( callback /*, initialValue*/ ) {
        'use strict';
        if ( null === this || 'undefined' === typeof this ) {
          throw new TypeError(
             'Array.prototype.reduce called on null or undefined' );
        }
        if ( 'function' !== typeof callback ) {
          throw new TypeError( callback + ' is not a function' );
        }
        var t = Object( this ), len = t.length >>> 0, k = 0, value;
        if ( arguments.length >= 2 ) {
          value = arguments[1];
        } else {
          while ( k < len && ! k in t ) k++; 
          if ( k >= len )
            throw new TypeError('Reduce of empty array with no initial value');
          value = t[ k++ ];
        }
        for ( ; k < len ; k++ ) {
          if ( k in t ) {
             value = callback( value, t[k], k, t );
          }
        }
        return value;
      };
    }
    

    所有内容都未经测试,但我最近回答了一个类似的问题 here,并带有指向小提琴的链接。

    【讨论】:

      【解决方案2】:

      事实证明,在 jQuery-1.8 之前,使用一个参数调用 $.then() 等同于调用 $.then(successFunction, successFunction)。由于我使用的是 jQuery-1.7.1,因此被拒绝的 Promise 仍会调用递归。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-19
        • 1970-01-01
        • 2021-07-15
        • 2014-12-18
        • 1970-01-01
        • 2020-09-04
        • 1970-01-01
        相关资源
        最近更新 更多