Я попытался создать скребок, используя функцию 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 и никогда не прогрессирует. [Я также пытался использовать обещание вместо стиля обратного вызова, но все тот же вывод.]
Где я ошиблась?
Проблема заключается в том, что состояние в 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: обзор движка, времени выполнения и стека вызовов
Вы можете попробовать использовать рекурсию, чтобы она не застревала в этом цикле?
// loop function
function testloop() {
console.log('checkpoint 1'); // checkpoint
scrape('https://www.google.com/', (sometext) => {
console.log('checkpoint 4', sometext); // checkpoint
testLoop();
});
}