我有以下方法:
function getRelevantArticles(amount,
userSuggestions,
suggestionPage,
relevantArticles,
continueFlag,
success,
error)
{
if(continueFlag)
{
getSuggestedArticles(suggestionPage, userSuggestions, function (articles)
{
if(articles.length == 0)
getRelevantArticles(amount, userSuggestions, suggestionPage, relevantArticles, false, success, error); // continueFlag= false
getUnvisitedArticles(articles, function (unvisited)
{
for(var i = 0; i < unvisited.length; i++)
relevantArticles.push(unvisited[i]);
relevantArticles= filterRelevant(amount, userSuggestions, relevantArticles);
if(relevantArticles.length < amount)
getRelevantArticles(amount, userSuggestions, suggestionPage + 1, relevantArticles, true, success, error); // continueFlag= true
else
getRelevantArticles(amount, userSuggestions, suggestionPage, relevantArticles, false, success, error); // continueFlag= false
}, error);
}, error);
}
else if(success)
{
fillWithContent(relevantArticles, success, error); //Should be last method to execute
}
}语境
我知道它可能很难理解,并且可以进行很多优化,我将尽我所能来解释它正在做什么(或试图):
该方法首先使用continueFlag= true标志进行调用,因此它首先调用getSuggestedArticles,这是一个发出AJAX请求的异步方法。我传入一个回调函数,并得到请求的结果。
getSuggestedArticles为我提供了与用户建议相关的文章Ids。(用户建议是用户可能感兴趣的主题列表)。
我通过了一个suggestionPage,因为建议可能很多,我应该能够得到相关的文章只有几个(第一页)。
如果没有检索到文章,那么就意味着我们没有建议(每个建议至少有一篇文章),也就是说,我们到达了最后一页,因此我们将continueFlag标志设置为false,以调用终结器方法。
如果至少有一篇文章,我将调用getUnvisitedArticles,这是另一种发出AJAX请求的异步方法。这个方法给出了用户没有访问或阅读的文章,这些都是我关心的文章。
我有一个relevantArticles变量,它跟踪我发现的相关文章,并将提供给用户。一旦我从我当前未访问过的文章中获得了相关的文章,并将它们附加到上一页的相关文章中,我就会检查我是否有要显示的文章的最小amount。
如果我还没有满足最小数量,那么我继续下一页(suggestionPage + 1);
如果达到最小阈值,则继续使用终结器方法(continueFlag= false)。
fillWithContent是在我识别完相关文章之后将被调用的方法。它是一种异步方法,它将发出AJAX请求,并将补充信息填充我的文章对象。
getSuggestedArticles(编号: suggestionPage,数组: userSuggestions,函数:成功,函数:错误)
接收用户建议数组,并接受该数组的第n页(页大小100)。
让我们假设我们这样调用这个方法:
getSuggestedArticles(0, [ 745, 4567, 1500 ], function (data) {
var articles = data;
}, error);该方法向Database发出请求,并将建议的文章数组传递给success函数。在前面的示例中,articles变量将有一个类似于此的数组(请注意,所有返回的建议文章在其主题中至少有一个用户建议):
[
{
id: 12345,
topics: [ 998, 1500, 323 ] //has user suggestion 1500
},
{
id: 45778,
topics: [ 009, 1500, 745] //Has user suggestion 745 and 1500
},
...
]getUnvisitedArticles(数组:文章,函数:成功,函数:错误)
接收一组文章,并返回所有未被用户访问的文章。
让我们假设我们这样调用这个方法:
//We are using the same "articles" variable from the previous example
getUnvisitedArticles(articles, function (data) {
var unvisited = data;
}, error); 该函数向Database发出请求,并将一个带有未访问项目的数组传递给success函数。在前面的示例中,变量unvisited具有如下所示的数组:
[
{
id: 45778,
topics: [ 009, 1500, 745]
}
]注意,id 12345的文章已经消失。这是因为用户已经访问了它。
fillWithContent(数组: relevantArticles,函数:成功,函数:错误)
接收一组项目,并使用其他信息填充这些对象。
让我们假设我们这样调用这个方法:
//We are using the same "unvisited" variable from the previous example
fillWithContent(unvisited, function (data) {
filledArticles = data;
}, error);该函数向Database发出请求,并向success函数传递一个包含已填充文章的数组。在前面的示例中,变量filledArticles具有如下所示的数组:
[
{
id: 45778,
topics: [009, 1500, 745],
title: 'Article title',
publicationDate: 'Some date',
author: 'Some author',
...
}
]--这是我的调用方正在驱逐的数组,调用者我指的是调用我的getRelevantArticles函数的数组。
问题所在
这个方法的问题是,fillWithContent 被无限地调用,从而导致大量请求被发出,浏览器崩溃,以及递归溢出产生。
我不是从另一个地方调用这个方法,所以它必须是这个函数的一个问题。
我写了一个console.log(suggestionPage),它似乎也在无止境地递增变量。它应该在页面3停止,因为articles.length == 0。但它并没有停止。
这里发生什么事情?
发布于 2015-08-05 17:56:59
我认为您应该将您的工作负载分成一些独立的部分,这些部分很容易解释,也可以很容易地结合起来,以获得更复杂的结果。
据我了解,这项工作由三个基本部分组成,所有这些部分都是通过Ajax完成的:
所有这些Ajax请求都应该以分页的方式进行,例如,由10个请求处理1000个项目,每个请求100个条目。
为此,我们定义了一个实用函数,它接收项目列表,分页,为每个页面发出Ajax请求(通过我们作为参数传递的worker函数),并返回所有请求的合并结果。
// utility: runs an ajax request and handles errors on the low level
function ajax(options) {
return $.ajax(options).fail(function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown, jqXHR);
});
}
// utility: makes paged Ajax requests through a worker function
function pagedAjax(ajaxFunc, items, pageSize) {
var temp = [].slice.call(items), page,
requests = [];
// start as many parallel Ajax requests as we have pages
while (temp.length) {
page = temp.splice(0, pageSize);
requests.push( ajaxFunc(page) );
}
// wait until all requests have finished, return combined result
return $.when.apply($, requests).then(function (results) {
var combined = [];
$.each(results, function (i, result) {
// result is an array [data, textStatus, jqXhr]
// push all contained items onto combined
// (the following assumes that data is an array of objects)
[].push.apply(combined, result[0]);
});
return combined;
});
}现在,我们可以设置我们的三个工人的功能。它们接受任意数量的输入,因为所有分页都是由上面的实用程序函数完成的:
// worker: retrieves a list of article IDs from topic IDs
function getSuggestedArticles(topics) {
return ajax({method: 'post', url: '/articlesByTopic', data: topics});
// or whatever API request returns a list of articles IDs from topic IDs
}
// worker: takes a list of article IDs, returns a list of _unread_ article IDs
function getUnvisitedArticles(articles) {
return ajax({method: 'post', url: '/unvisitedArticles', data: articles});
// or whatever API request returns a list of unvisited articles from IDs
}
// worker: takes a list of article IDs, returns a list of articles
function fillWithContent(articles) {
return ajax({method: 'post', url: '/articles', data: articles});
// or whatever API request fills articles with content
}在此之后,合并这些功能不再困难:
// takes a list of topic IDs, requests article IDs, filters them, returns actual articles
function getUnvisitedArticlesByTopic(topicIds) {
var pageSize = 100;
return pagedAjax(getSuggestedArticles, topicIds, pageSize)
.then(function (allArticles) {
return pagedAjax(getUnvisitedArticles, allArticles, pageSize);
})
.then(function (unvisitedArticles) {
return pagedAjax(fillWithContent, unvisitedArticles, pageSize);
});
}我们可以通过一个非常简单的调用来使用它:
// renders unvisited articles
function renderUnvisitedArticles() {
var topicIds = [9, 1500, 745];
getUnvisitedArticlesByTopic(topicIds).done(function (articles) {
$.each(articles, function (i, article) {
// show article on page
});
});
}这种基于承诺的方法的好处:
推荐阅读当然是jQuery关于延迟对象的文档。
免责声明:代码确实未经测试。如果你发现了错误,告诉我。
https://stackoverflow.com/questions/31835492
复制相似问题