延迟节点js中的每个循环迭代,async

use*_*355 13 javascript for-loop node.js

我有以下代码:

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);
    });
Run Code Online (Sandbox Code Playgroud)

有没有人有关于如何延迟每个循环迭代的建议for loop?比如说,代码在每次迭代完成后等待10秒.我尝试setTimeout但没有管理那个工作.

Tro*_*ott 16

您可以按以下间隔设置执行代码的超时时间,如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

所以第一个立即运行(间隔*0为0),第二个运行十秒后运行等.

您需要发送i最终参数,setTimeout()以便将其值绑定到函数参数.否则,访问数组值的尝试将超出范围,您将获得undefined.

  • `setTimeout()` 立即返回。它不会坐在那里等待超时,然后再将控制权返回给 `for` 循环。因此,如果您使用 `interval * 1`(与 `interval` 相同,那么您将在未来 10 秒内一次性运行所有内容(或多或少 - 它们将相隔几毫秒,但仅此而已) ). 但是如果你使用`interval * i`,第一次是“马上”,第二次是“未来十秒”,第三次是“未来二十秒”,以此类推。 (2认同)

Rod*_*ros 16

另一种选择是使用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();
});
Run Code Online (Sandbox Code Playgroud)


Luc*_*iva 16

使用延迟多个页面提取 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
}
Run Code Online (Sandbox Code Playgroud)

好多了,不是吗?在我进入的是如何在细节fetchPage()fetchUrls()做工,让我们先回答你的,以获取下一个页面之前如何等问题.睡眠功能非常简单:

async function sleep(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处获得有关其工作原理的完整说明.

好的,回到其他功能.该request库具有可以使用的启用承诺的版本async/await.我们来看看如何fetchPage()实施:

async function fetchPage(url) {
    return await request({
        url: url,
        transform: (body) => cheerio.load(body)
    });
}
Run Code Online (Sandbox Code Playgroud)

既然request回来了承诺,我们就可以await了.我也抓住机会使用了transform允许我们在解决承诺之前转换响应主体的属性.我将它传递给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();
Run Code Online (Sandbox Code Playgroud)

request与promises一起使用,请按以下方式安装:

npm install request
npm install request-promise-native
Run Code Online (Sandbox Code Playgroud)

然后require("request-promise-native")在你的代码中,就像上面的例子一样.


aps*_*ers 10

既然你已经在使用async,async.wilst那么就可以很好地替代它for.

whilst是一个while类似异步的函数.每次迭代仅在前一次迭代调用其完成回调之后运行.在这种情况下,我们可以简单地将完成回调的执行推迟10秒setTimeout.

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
);
Run Code Online (Sandbox Code Playgroud)


小智 6

以下是在 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);
}
Run Code Online (Sandbox Code Playgroud)