Как справиться с обещанными рекурсиями - PullRequest
0 голосов
/ 17 января 2020

У меня есть автоматический скрипт, написанный на javascript, задача, которую он должен выполнить sh - нажать кнопку Get Tasks, которая вызывает вызов ajax, и результаты вызова отображаются в таблице, следующий шаг для проверки таблицы, если есть задача, скрипт принимает ее, нажимая кнопку Accept, в противном случае сценарий нажимает кнопку Get Tasks. Задача кажется простой, поэтому я написал следующий скрипт:

function clickGetTasksButton() {
    return new Promise(resolve => {
        document.getElementsByClassName("get-tasks-btn").click();
        resolve();
    });
}
function waitForSpinner() {
    return new Promise((resolve) => {
        let spinInterval = setInterval(() => {
            let spinner = document.querySelector('.spinner');
            if (!spinner) {
                console.log("Spinner is gone... ");
                clearInterval(spinInterval);
                resolve(document.getElementsByClassName("task-card").length > 0)
            }
        }, 50)
    });
}
function driver() {
    clickGetTasksButton().then(() => {
        waitForSpinner().then((result) => {
            //Script should either accept task or repeat the whole process
        });
    });
}

Я пытаюсь добавить следующие логи c: если есть кнопка Accept, нажмите на нее, в противном случае нажмите кнопку Get Tasks и повторение. Я думал об использовании рекурсий, но боюсь, что в какой-то момент это вызовет исключение переполнения стека.

1 Ответ

2 голосов
/ 17 января 2020

Вы можете просто свободно возвращаться из обработчика .then(). Поскольку стек уже полностью размотан до вызова обработчика .then(), при повторном вызове driver() или любой другой функции верхнего уровня, которую вы хотите вызывать из обработчика .then(), не происходит наращивание стека.

Например, вы можете сделать это:

function driver() {
    return clickGetTasksButton().then(() => {
        waitForSpinner().then((result) => {
            //Script should either accept task or repeat the whole process
            if (taskWaiting) {
                return processTasks();
            } else {
                return driver();
            }
        });
    });
}

или немного сгладить:

function driver() {
    return clickGetTasksButton().then(waitForSpinner).then(result => {
        //Script should either accept task or repeat the whole process
        if (taskWaiting) {
            return processTasks();
        } else {
            return driver();
        }
    });
}

Также обратите внимание, что clickGetTasksButton не нужно возвращать обещание поскольку это кажется полностью синхронным. Кроме того, вы не можете напрямую позвонить .click() по результатам document.getElementsByClassName(). Эта функция возвращает массивоподобный список (объект HTMLCollection), у которого нет метода .click(). Я не знаю, намереваетесь ли вы получить первый элемент DOM в этом списке и вызывать .click() для него или если вы хотите l oop через список, вызывая .click() для каждого.

И ваш setInterval(), вероятно, должен использовать немного больший интервал, чем 50 мс. Вы хотите дать несколько циклов самой веб-странице, чтобы сделать свою работу. Вы как бы забиваете это здесь 20 раз в секунду. Я бы сказал, установить его на что-то вроде 200. И, надеюсь, это не займет много времени для запуска, потому что, если это мобильное устройство, это увеличит время автономной работы и, возможно, даже вытеснит браузер хоста (для экономии заряда батареи).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...