簡體   English   中英

延遲節點js中的每個循環迭代,async

[英]Delay each loop iteration in node js, async

我有以下代碼:

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但沒有管理它。

您可以按以下間隔設置執行代碼的超時時間,如下所示:

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

另一種方法是使用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();
});

使用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));
}

您可以在此處獲得有關其工作原理的完整說明。

好的,回到其他功能。 request庫具有啟用了承諾的版本,您可以將其與async/await 我們來看看fetchPage()如何實現的:

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

由於request正在返回一個承諾,我們可以await它。 我也有機會使用transform屬性,它允許我們在解析promise之前轉換響應體。 我將它傳遞給Cheerio,就像你在代碼中所做的那樣。

最后, fetchUrls()可以在解析其promise之前調用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();

要使用promises request ,請按以下方式安裝:

npm install request
npm install request-promise-native

然后在代碼中require("request-promise-native") ,如上例所示。

由於你已經在使用asyncasync.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
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM