Асинхронная функция заклинило при использовании внутри цикла while (scraperjs)

1

Я попытался создать скребок, используя функцию ruipgil/scraperjs, которая является асинхронной. Но когда я положил его внутри цикла, он застрял и не сработает. Я новичок в Node и идея асинхронного программирования, поэтому, пожалуйста, несите меня.

Итак, у меня есть этот код:

let scraperjs = require('scraperjs');

// scraper function
function scrape(pageURI, callback) {
    console.log('checkpoint 2'); // checkpoint
    scraperjs.StaticScraper.create(pageURI).scrape(function($) {
        console.log('checkpoint 3'); // checkpoint
        return $("div").map(function() {
            return $(this).text();
        }).get();
    }).then(function(sometext) {
        callback(sometext);
    });
}

// loop function
function testloop() {
    let finished = false;
    let processed = false;

    while (!finished) {
        if (!processed) {
            console.log('checkpoint 1'); // checkpoint
            scrape('https://www.google.com/', (sometext) => {
                console.log('checkpoint 4', sometext); // checkpoint
                finished = true;
            });
            processed = true;
        }
    }
}

// non loop function
function testnonloop() {
    console.log('checkpoint 1'); // checkpoint
    scrape('https://www.google.com/', (sometext) => {
        console.log('checkpoint 4', sometext); // checkpoint
    });
}

Я попытался отправить обе функции, ожидая выхода 4 контрольных точек. Но странно, что один с петлей застрял в контрольной точке 2 и никогда не прогрессирует. [Я также пытался использовать обещание вместо стиля обратного вызова, но все тот же вывод.]

Где я ошиблась?

Теги:
web-scraping
asynchronous

2 ответа

1
Лучший ответ

Проблема заключается в том, что состояние в while петля никогда не изменится, так как функция обратного вызова никогда не будет выполнена.

Это происходит из-за того, что программы JavaScript выполняются в Event Loop. Механизм JavaScript имеет стек вызовов (который записывает, где находится в нашей программе) и очередь обратного вызова (которая отслеживает выполнение асинхронных обратных вызовов).

Event Loop контролирует стек вызовов и очередь обратного вызова. Если стек вызовов пуст, он будет принимать первое событие из очереди обратного вызова и вытолкнет его в стек вызовов, который его запускает.

В вашем случае Call Stack никогда не пустеет, он всегда занят в while цикл, так что обратный вызов никогда не выполняется, так что в while условие всегда true.

Возможным решением для вас может быть использование setTimeout для вызова scrape до тех пор, пока не будет вызван первый обратный вызов. С помощью setTimeout вы освободите стек вызовов, позволяя выполнять асинхронные вызовы.

// loop function
function testloop() {
    let finished = false;

    function loop () {
        if (!finished) {
            console.log('checkpoint 1'); // checkpoint
            scrape('https://www.google.com/', (sometext) => {
                console.log('checkpoint 4', sometext); // checkpoint
                finished = true;
            });
            setTimeout(loop, 0);
        }
    }
    loop();
}

Вы можете найти более подробное объяснение Loop Event здесь: Как работает JavaScript: обзор движка, времени выполнения и стека вызовов

  • 0
    так что, в принципе, «вызов в то время как терминатор асинхронно плох», я прав? Но что мне делать, если я хочу запустить, а затем удалить очередь асинхронных задач, пока очередь не станет пустой?
  • 0
    Я обновил свой ответ, добавив пример, который позволит выполнять асинхронный код во время цикла.
1

Вы можете попробовать использовать рекурсию, чтобы она не застревала в этом цикле?

// loop function
function testloop() {
    console.log('checkpoint 1'); // checkpoint
    scrape('https://www.google.com/', (sometext) => {
        console.log('checkpoint 4', sometext); // checkpoint
        testLoop();
    });
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню