PhantomJS - метод WaitFor не будет выполнять функцию. Программа застряла

У меня возникли некоторые проблемы с использованием waitFor-метода в PhantomJS.

Вот что я хочу сделать:

  • Загрузка нескольких веб-страниц по сгенерированным URL
  • Используйте jQuery для анализа некоторых ссылок с этих страниц.
  • Сохраните каждую проанализированную ссылку в одном массиве (в этом примере я просто зарегистрирую их)

Я использую метод waitFor (), так что я могу ждать, пока страница не будет оценена. Как я понимаю, этот метод не позволит программе продолжаться до тех пор, пока функция, которую я передаю в качестве параметра, не выдаст ничего.

Моя проблема: На самом деле программа не будет продолжать работать после выполнения waitFor-Method. Это просто застряло. Там нет никакой ошибки вообще. Функция, которую я передал в качестве параметра, не будет выполнена... по крайней мере, в консоли нет регистрации.

Когда я удаляю waitFor-Methot, он будет правильно выполнять код, однако я не могу выполнить метод handleSeriesPageListPage ()- несколько раз. Я действительно не слишком увлекаюсь js и callbacks или асинхронной обработкой методов. Я думаю, что я сделал несколько серьезных ошибок, и некоторые эксперты по javascript смогут мне быстро помочь:).

"use strict";
var page = require('webpage').create();
page.onConsoleMessage = function (msg) {
    console.log(msg);
};
var seriesPageBaseUrl = "https://www.example.com?pageid=";
var simpleBaseUrl = "https://www.example.com/";
var seriesPageIds = [0xx, 1xx];
var allSeriesUrls = [];


function handleSeriesPageListPage(url) {
    console.log("Open url: " + url);
    page.open(url, function (status) {
        console.log("status: " + status);
        if (status === "success") {
            waitFor(
                function () {
                    return page.includeJs("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {
                        console.log("Included JS");
                        return page.evaluate(function () {
                            console.log("evaluate result...");
                            $('.list_item').each(function () {
                                var seriesLink = jQuery(this).find("a").first().attr("href");
                                var seriesUrl = simpleBaseUrl + seriesLink;
                                console.log(seriesUrl);
                                return true;
                            });
                        });
                    });
                }
            );
        } else {
            phantom.exit(1);
        }
    });
}

function nextSeriesListPage() {
    var seriesPageId = seriesPageIds.shift();
    if (typeof seriesPageId === "undefined") {
        console.log(allSeriesUrls);
        phantom.exit(0);
    }
    var targetURL = seriesPageBaseUrl + seriesPageId;
    handleSeriesPageListPage(targetURL);
}

nextSeriesListPage();

1 ответ

Решение

waitFor() Используемая вами функция не подходит для обработки асинхронных задач, и вы на самом деле неправильно поняли, что она делает:

waitFor(testFx, onReady, timeOutMillis)

принимает три параметра (третий необязательный). Первый параметр - это тестовая функция. Он выполняется многократно, но каждый раз синхронно, пока его возвращаемое значение не будет true, Затем выполняется функция, заданная в качестве второго параметра. Если в течение периода, заданного третьим параметром (или 3 секунды по умолчанию), нет true значение возвращается, функция завершается с сообщением журнала 'waitFor()' timeout,

Вы предоставили только один параметр; функция, которая завершается без возвращаемого значения (page.includeJs(), в принципе). Соответственно, waitFor() должен выйти через 3 секунды с timeout сообщение.

То, чего вы действительно хотели достичь, было

  • дождитесь загрузки страницы
  • затем вставьте скрипт jQuery и дождитесь этого,
  • затем переоценить, и ждать этого,
  • затем извлекать информацию

Это четыре асинхронных задачи. Основной подход, предписанный PhantomJS, состоит в том, чтобы перейти к соответствующему следующему шагу внутри предыдущей функции обратного вызова, что приводит к четырем вложенным обратным вызовам.

Поскольку это не очень хороший шаблон (его обычно называют адом обратного вызова), шаблон Promise был представлен как функция Javascript (или включен в несколько библиотек).

Чтобы узнать, как переформулировать API обратного вызова в качестве Promises, взгляните на Как преобразовать существующий API обратного вызова в обещания?

Другие вопросы по тегам