无法使用$ .Deffered()对象和$ .then()破坏递归 [英] Cannot break recursion with $.Deffered() object and $.then()

查看:115
本文介绍了无法使用$ .Deffered()对象和$ .then()破坏递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have to search through word index tables with potentially hundreds of thousands rows. I can restrict my search by passing a list of documents to the search. Request to search for words in many documents return very slowly. So...to improve the UX we're chunking the request into several groups of documents. So, if a user asks to search 90 documents, and the chunk size is 10 documents per query, then we send out 90 / 10 = 9 independent $.ajax() calls. We want the results to come in the order they were sent.

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()的状态.也就是说,当下一行

When I debug the code, it appears that deferred.reject() does not change the state of deferred.promise(). That is, when the next line

return deferred.promise().then(RecursiveSearch)

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

is executed, it just loops back into the recursive function, instead of exiting the recursion and falling into

RecursiveSearch().fail(SomeFunction);

重要提示:

我正在使用 jQuery-1.7.1 .我在 JSFiddle 中进行了类似的递归(谢谢

Important Note:

I'm using jQuery-1.7.1. I ran analogous recursion in JSFiddle (Thank you Beeetroot-Beetroot) and it failed on jQuery-1.7.2 while on jQuery-2.1.0 it ran without a problem.

关于如何使递归在 jQuery-1.7.1 中工作的任何想法?

Any idea on how to get the recursion to work in jQuery-1.7.1?

推荐答案

提供了部分覆盖您所要查找内容的模式 此处 ,位于标题"The Kerfuffle Collection"下.实际上,您实际需要的略多于此,这是因为您想以块(组)的形式访问文档引用列表.

A pattern partly covering what you are looking for is provided here under the heading "The Collection Kerfuffle". You actually need slightly more than that because you want to address your list of document referneces in chunks (groups).

代码将如下所示:

$(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之前的版本)则没有.

You also need the Polyfill for Array.prototype.reduce, as .reduce is relied on above and older browsers (pre ECMAScript5) don't have it.

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;
  };
}

所有未经测试,但我最近在 此处 回答了类似的问题,并带有小提琴的链接

All untested but I recently answered a similar question here, with a link to a fiddle.

这篇关于无法使用$ .Deffered()对象和$ .then()破坏递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆