迭代迭代中的setTimeout

我有下面的代码,我想在每次Myurl迭代之间放置setTimeout 。 有许多classes ,每个classes都包含许多元素。

 //Some calculations before... var i = 0; async.whilst( function () { return i <= thefooz.length - 1; }, function (innerCallback) { //Some calculations where I get classes array. async.forEachOfSeries(classes, function (Myurl, m, eachDone) { // Here I want a delay async.waterfall([ function (next) { connection.query( 'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl], next ); }, function (results, fields, next) { if (results.length !== 0) { console.log("Already Present"); return next(); } console.log("New Thing!"); request(options2, function (err, resp, body) { if (!err && resp.statusCode == 200) { var $ = cheerio.load(body); //Some calculations, where I get AllLinks. var post = { ThisUrl: AllLinks[0], Time: AllLinks[1], }; var query = connection.query('Insert INTO mydata Set ?', post, next); }; }); } ], eachDone); }, function (err) { if (err) throw err; }); setTimeout(function () { i++; innerCallback(); console.log("Done"); }, 20000); //Some calculations after... 

那么我怎么能在Myurl中的每个Myurl之间设置一个延迟? 说我想要5秒钟的延迟。 我设法setTimeout之间的每个async.whilst迭代,但不是每个async.forEachOfSeries迭代之间。 它根本不会等待,而是继续循环,直到每个async.forEachOfSeries完成,然后调用async.whilst setTimeout

EDIT :队列解决scheme不起作用。 该解决scheme似乎只是进入下一页和下一页等,而不会输出到我的数据库。 当然,我可以用错误的方式来应用,但是我真的试图按照例子的说法去做。

我想你并不完全理解setTimeout是如何工作的:

 (function () { var seconds=0; [1,2,3].forEach(function(value) { setTimeout(function() { console.log('Showing value '+value+ 'at '+Date()); },1000*seconds++); }) })() 

这个代码为每个元素创build一个callback函数,在一秒之后执行。 请注意,JS是单线程的,所以代码真正做的是将“执行”添加到队列中。 所以如果当前的执行不停止,callback不会被调用。 因此,作为第二个parameter passing给setTimeout函数的时间(以毫秒为单位)只是执行代码的最短时间。

然后,这些callback的执行按照先进先出顺序进行。

更新 :这是我正在解释的一个例子:

 function myFunction() { var test=0; setTimeout(function(){ console.log("This is the current value of test: "+test); }, 0); console.log("This is run first"); for (var i=0;i<50;i++) { test++; } console.log("Main thread ending, not the callbacks will be executed"); } 

setTimeout将在执行前等待0(零),但由于主线程还没有完成,所以不能执行。 然后,当循环结束时,执行callback,发现testing是50,而不是0。

首先我们必须实现一个简单的队列

队列

 function Queue() { var obj = {}; var queue = []; var _delay; function next() { // If queue is empty stops execution if(queue.length == 0) return; // Prepare next call to next setTimeout(next, _delay); // Take out an element from the queue and execute it. (queue.shift())(); } // Add a new function to the queue obj.add = function (myFunc) { queue.push(myFunc); }; // Start the queue execution passing the delay between each call obj.run = function(delay) { _delay = delay; // call next function next(); } return obj; } 

然后我们在代码中使用它

 // create the queue var myQueue = Queue(); async.forEachOfSeries(classes, function (Myurl, m, eachDone) { // Add the function to the queue myQueue.add(executeWaterfall.bind(this)); }, function (err) { if (err) throw err; }); // Start the queue with 5 second delay myQueue.run(5000); function executeWaterfall() { async.waterfall([ function (next) { connection.query( 'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl], next ); }, function (results, fields, next) { if (results.length !== 0) { console.log("Already Present"); return next(); } console.log("New Thing!"); request(options2, function (err, resp, body) { if (!err && resp.statusCode == 200) { var $ = cheerio.load(body); //Some calculations, where I get AllLinks. var post = { ThisUrl: AllLinks[0], Time: AllLinks[1], }; var query = connection.query('Insert INTO mydata Set ?', post, next); }; }); } ], eachDone); } 

这远远不是最理想的,因为无论如何,你陷入了厄运金字塔

奖金

末日金字塔

当用普通的callback函数连续地处理asynchronous操作时,你将最终嵌套调用对方; 这个嵌套来更多的缩进,创build一个金字塔(指向右侧),因此,名称“末日金字塔”。

在这种情况下,最好使用一些承诺模式来保存来自厄运金字塔的代码,并便于解决这类问题。

  • 更多信息
  • PromiseJS

我不是很熟悉async库,但对我来说,看起来像async.waterfall将在每次运行后调用eachdone ,以便async.forEachOfSeries知道它应该执行下一个迭代。 假设eachdone被调用没有参数,我期望以下工作:

 function executeWaterfall() { async.waterfall([ ...... ], function () { window.setTimeout(eachDone, 5000)); } 

如果eachdone都得到参数,你也必须发送它们。

作为另一种select,我希望你可以在瀑布上增加另一个步骤,等待5秒钟。 这将工作,无论eachdone参数(但可能会失败,如果第三个瀑布function期望更多的paraneters):

 function executeWaterfall() { async.waterfall([ function (next) { connection.query( 'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl], next ); }, function (results, fields, next) { if (results.length !== 0) { console.log("Already Present"); return next(); } console.log("New Thing!"); request(options2, function (err, resp, body) { if (!err && resp.statusCode == 200) { var $ = cheerio.load(body); //Some calculations, where I get AllLinks. var post = { ThisUrl: AllLinks[0], Time: AllLinks[1], }; var query = connection.query('Insert INTO mydata Set ?', post, next); }; }); }, function (next) { window.setTimeout(next, 5000); } ], eachDone); } 

现在,我想再次强调,我不熟悉async ,所有的例子都没有经过testing。 也许一切都大错特错,但这是我的直觉。

setTimeout只会延迟结果显示在输出中……它不会延迟setTimeout方法内部或外部方法的执行…在后台线程将继续运行setTimeout函数之后的代码…由于你正在使用asynchronous你需要使用完整的Ajax方法,当你完成从服务器接收到的所有数据