Javascript не может передать Vars/Fn в область .evaluate() (NightmareJS)

Я пытаюсь передать переменную .evaluate, чтобы использовать ее в рамках веб-страницы, но не могу заставить ее работать.

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    })

    .evaluate(function(result) {
        for(var i = 0; i < result.length; i++) {
            var matchResult = result[i].match(/.com\/(.*?)\?fref/);
            if (matchResult) {
                console.log(matchResult[1]);
            }
        }
    });

За это я получаю Cannot read property 'match' of undefined. Затем я попытался:

const evaluated = await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    });

    await nightmare.evaluate(function(evaluated) {
        for(var i = 0; i < evaluated.length; i++) {
            var matchResult = evaluated[i].match(/.com\/(.*?)\?fref/);
            if (matchResult) {
                console.log(matchResult[1]);
            }
        }
    });

С тем же результатом. Затем я попытался:

const evaluated = await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    });

for(var i = 0; i < evaluated.length; i++){
        var matchResult = evaluated[i].match(/.com\/(.*?)\?fref/);
        if(matchResult) {
            console.log(matchResult[1]);
            await nightmare.evaluate(function(matchResult) {
                return document.body.innerHTML += '<a href="https://www.example.com/'+matchResult[0]+'">'+matchResult[0]+'</a>';
            });
            await nightmare.click('a[href="https://www.example.com/'+matchResult[0]+'"]');
            await nightmare.wait(5000);
        }
    }
await nightmare.end();

Для этого выполняется первая итерация цикла и в консоль выводится matchResult[1]. Затем я получаю Error: Evaluation timed out after 30000msec. Are you calling done() or resolving your promises?.

Я также пробовал что-то вроде этого:

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    }).then(function(users){

    }).end();

Что передает возврат в .then(), но как передать массив в следующую оценку? И теперь это последнее, о чем я могу думать, но не работает:

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    }).evaluate((users) => {
        console.log(users);
    }).end();

Я нашел решение здесь, но оно возвращает мне undefined. Я также нашел это, в котором говорится об аналогичной вещи в PhantomJS, но еще не придумали работоспособный код.


person xendi    schedule 29.09.2017    source источник
comment
Array.prototype.forEach возвращает undefined. Используйте Array.prototype.find.   -  person Noah Freitas    schedule 30.09.2017
comment
Что такое nightmare.evaluate? То, что у вас есть, не похоже на обещание, и это единственное, что await может контролировать. По крайней мере, так, как вы ожидаете.   -  person Andrew    schedule 30.09.2017
comment
Я обновил вопрос, добавив лучший пример проблемы и несколько версий кода, которые мне надоели. Я смог решить предыдущий код, который я разместил, с помощью Array.prototype.find, но код, который мне пришлось написать сразу после этого, страдает от той же проблемы, которую find не решит.   -  person xendi    schedule 30.09.2017
comment
Обновлено снова с большим количеством попыток.   -  person xendi    schedule 30.09.2017
comment
В первой попытке измените вторую .evaluate() на .then() с тем же телом функции.   -  person Patrick Roberts    schedule 30.09.2017
comment
Да, но код, который мне нужен в .then, мне нужно, чтобы он работал в контексте веб-страницы. Вот для чего нужен .evaluate. Я попробую это все же.   -  person xendi    schedule 30.09.2017
comment
Обновленный вопрос внизу с еще двумя решениями, которые я пытаюсь использовать. Также обновлен заголовок вопроса, чтобы лучше отразить проблему.   -  person xendi    schedule 01.10.2017
comment
Опубликовал ответ.   -  person xendi    schedule 01.10.2017


Ответы (1)


Я нашел ответ. Кажется, что половина моих попыток, вероятно, сработала, и я просто не осознавал этого. В рамках .evaluate() мы находимся в области браузера (как и предполагалось), но я не учел, что не могу войти в консоль из этой области. В частности, я не могу войти в свою консоль. Если я запускаю console.log из этой области, он регистрируется в консоли браузера. Работает следующий код:

    var foo = "stuff";
    var bar = "stuff for the remote page";

    var result = await nightmare.evaluate(function(bar2) {
        // this function executes in the remote context
        // it has access to the DOM, remote libraries, and args you pass in
        console.log("bla "+bar2); // this will not output
        // but not to outer-scope vars
        return typeof foo + " " + bar2;
    }, bar);
    console.log(result); // this logs bar2!

Я думаю, что это решает. Может быть немного сложно отладить то, что происходит в области документа, но, безусловно, возможно.

person xendi    schedule 30.09.2017