我有以下代码:
var request = require('request');
var cheerio = require ("cheerio");
var async= require("async");
var MyLink="www.mylink.com";
async.series([
function(callback){
request(Mylink, function (error, response, body) {
if (error) return callback(error);
var $ = cheerio.load(body);
//Some calculations where I get NewUrl variable...
TheUrl=NewUrl;
callback();
});
},
function(callback){
for (var i = 0; i <=TheUrl.length-1; i++) {
var url = 'www.myurl.com='+TheUrl[i];
request(url, function(error, resp, body) {
if (error) return callback(error);
var $ = cheerio.load(body);
//Some calculations again...
callback();
});
};
}
], function(error){
if (error) return next(error);
});
是否有人建议如何延迟for loop
中的每个循环迭代?比如说,代码在每次迭代完成后等待10秒。我尝试了setTimeout
,但没有设法解决这个问题。
答案 0 :(得分:15)
您可以按以下间隔设置执行代码的超时时间,如下所示:
var interval = 10 * 1000; // 10 seconds;
for (var i = 0; i <=TheUrl.length-1; i++) {
setTimeout( function (i) {
var url = 'www.myurl.com='+TheUrl[i];
request(url, function(error, resp, body) {
if (error) return callback(error);
var $ = cheerio.load(body);
//Some calculations again...
callback();
});
}, interval * i, i);
}
所以第一个立即运行(间隔* 0为0),第二个运行十秒后运行等等。
您需要在i
中发送setTimeout()
作为最终参数,以便将其值绑定到函数参数。否则,访问数组值的尝试将超出范围,您将获得undefined
。
答案 1 :(得分:15)
另一种选择是使用async.eachSeries
。例如:
async.eachSeries(TheUrl, function (eachUrl, done) {
setTimeout(function () {
var url = 'www.myurl.com='+eachUrl;
request(url, function(error, resp, body) {
if (error) return callback(error);
var $ = cheerio.load(body);
//Some calculations again...
done();
});
}, 10000);
}, function (err) {
if (!err) callback();
});
答案 2 :(得分:11)
async/await
我是异步库的忠实粉丝,而且我已经使用了很长时间。但是,现在有async/await
。您的代码变得更容易阅读。例如,这将是您的主要功能:
const urls = await fetchUrls(INITIAL_URL);
for (const url of urls) {
await sleep(10000);
const $ = await fetchPage(url);
// do stuff with cheerio-processed page
}
好多了,不是吗?在我详细了解fetchPage()
和fetchUrls()
的工作原理之前,让我们首先回答您在获取下一页之前如何等待的问题。睡眠功能非常简单:
async function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
您可以在我的其他答案here中获得有关其工作原理的完整说明。
好的,回到其他功能。 request
库具有启用许可的版本,可以与async/await
一起使用。我们来看看fetchPage()
实施的方式:
async function fetchPage(url) {
return await request({
url: url,
transform: (body) => cheerio.load(body)
});
}
由于request
正在返回承诺,我们可以await
。我也抓住机会使用transform
属性,它允许我们在解决promise之前转换响应主体。我将它传递给Cheerio,就像你在代码中所做的一样。
最后,fetchUrls()
可以调用fetchPage()
并处理它以获取您的URL数组,然后再解析其承诺。这是完整的代码:
const
request = require("request-promise-native"),
cheerio = require("cheerio");
const
INITIAL_URL = "http://your-initial-url.com";
/**
* Asynchronously fetches the page referred to by `url`.
*
* @param {String} url - the URL of the page to be fetched
* @return {Promise} promise to a cheerio-processed page
*/
async function fetchPage(url) {
return await request({
url: url,
transform: (body) => cheerio.load(body)
});
}
/**
* Your initial fetch which will bring the list of URLs your looking for.
*
* @param {String} initialUrl - the initial URL
* @return {Promise<string[]>} an array of URL strings
*/
async function fetchUrls(initialUrl) {
const $ = await fetchPage(initialUrl);
// process $ here and get urls
return ["http://foo.com", "http://bar.com"];
}
/**
* Clever way to do asynchronous sleep.
* Check this: https://stackoverflow.com/a/46720712/778272
*
* @param {Number} millis - how long to sleep in milliseconds
* @return {Promise<void>}
*/
async function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
async function run() {
const urls = await fetchUrls(INITIAL_URL);
for (const url of urls) {
await sleep(10000);
const $ = await fetchPage(url);
// do stuff with cheerio-processed page
}
}
run();
要将request
与promises一起使用,请按以下方式安装:
npm install request
npm install request-promise-native
然后在代码中require("request-promise-native")
,就像上面的示例一样。
答案 3 :(得分:9)
由于您已经在使用async
,async.wilst
可以很好地替代for
。
whilst
是一个异步while
的函数。每次迭代仅在前一次迭代调用其完成回调之后运行。在这种情况下,我们可以使用setTimeout
将完成回调的执行推迟10秒。
var i = 0;
async.whilst(
// test to perform next iteration
function() { return i <= TheUrl.length-1; },
// iterated function
// call `innerCallback` when the iteration is done
function(innerCallback) {
var url = 'www.myurl.com='+TheUrl[i];
request(url, function(error, resp, body) {
if (error) return innerCallback(error);
var $ = cheerio.load(body);
//Some calculations again...
// wait 10 secs to run the next iteration
setTimeout(function() { i++; innerCallback(); }, 10000);
});
},
// when all iterations are done, call `callback`
callback
);
答案 4 :(得分:0)
这是在 for 循环中提供延迟的示例代码。
const sleep = (milliseconds) => {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
};
for (let index = 0; index < 10; index++) {
console.log(index);
sleep(1000);
}