我有以下代码,我想在setTimeout
的每次迭代之间加上Myurl
。有许多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
中的每个async.waterfall
之间设置延迟?说我想延迟5秒。我设法在setTimeout
之间设置
每次async.whilst
迭代但不在每次async.forEachOfSeries
次迭代之间。它只是不等待,而是继续循环,直到每个async.forEachOfSeries
完成,然后调用async.whilst
setTimeout
。
EDIT
:
队列解决方案不起作用。该解决方案似乎只是转到下一页和下一页等,而不输出到我的数据库。当然我可以用错误的方式应用它,但我真的试着按照例子说的那样做。
答案 0 :(得分:7)
首先,我们必须实现一个简单的队列
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);
}
这远非最佳,因为无论如何你正陷入所谓的厄运金字塔
当使用正常回调连续处理异步操作时,您最终会在彼此之间嵌套调用;这种嵌套带来了更多的缩进,创造了一个金字塔(指向右边),因此得名“金字塔的厄运”。
在这种情况下,最好使用一些承诺模式将代码保存在厄运金字塔中,以便解决此类问题。
答案 1 :(得分:2)
我认为你并不完全理解setTimeout
如何运作:
(function () {
var seconds=0;
[1,2,3].forEach(function(value) {
setTimeout(function() {
console.log('Showing value '+value+ 'at '+Date());
},1000*seconds++);
})
})()
对于每个元素,此代码创建一个在一秒钟后执行的回调函数。请注意,JS是单线程的,因此代码实际上做的是将“执行”添加到队列中。因此,如果当前执行没有停止,则不会调用回调。因此,作为第二个参数传递给setTimeout
函数的时间(以毫秒为单位)只是执行该代码的最短时间。
然后,这些回调的执行是按FIFO顺序执行的。
更新:以下是我正在解释的示例:
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(零),但由于主线程尚未完成,因此无法执行。然后,当循环结束时,执行回调,发现测试为50,而不是0.
答案 2 :(得分:0)
我对async
库并不熟悉,但对我而言,async.waterfall
看起来每次运行后都会调用eachdone
,以便async.forEachOfSeries
知道它应该执行下一次迭代。假设没有参数调用eachdone
,我希望以下工作:
function executeWaterfall() {
async.waterfall([
......
], function () { window.setTimeout(eachDone, 5000));
}
如果eachdone
确实获得参数,您也必须将它们发送过来。
作为替代方案,我希望您可以在瀑布中添加另一个步骤,等待5秒。无论eachdone
的参数如何,这都可以工作(但如果第三个瀑布函数需要更多参数,则可能会失败):
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
并且所有示例都未经过测试。也许一切都是错误的,但这是我的直觉。
答案 3 :(得分:-3)
setTimeout只会延迟输出中显示的结果...它不会延迟setTimeout方法内部或外部方法的执行...在后台,线程将在setTimeout函数之后继续运行代码。 ..既然你正在使用异步,你就要使用ajax的COMPLETE方法,当你完成从服务器收到所有数据后将调用该方法