@valentine11

Неправильно работает промис, чяднт?

Есть задача: получить некие данные со страницы, сформировать урлы с этими данными, затем отправить запросы к урлам и в респонзе провести проверку.
Составлен такой код:
function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return search.forEach(function(val, i) {
                    console.log(search.length); //debug printing
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        console.log(body);
                        assert.include(body, 'class="someClass"');
                    });
                });
            });

        }

        return checkSpec();

Но работает он неправильно. Сначала идет перебор массива, степ теста якобы благополучно проходит, начинаются другие степы, и где-то посередине начинают приходить ответы (вывод body в консоль).
Где что нужно поправить в промисе, чтобы оно работало нормально? Т.е. на каждый элемент массива - запрос - проверка, и только потом на следующий элемент массива запрос-проверка и т.д.

UPD.
Изменив код в соответствии с рекомендациями, получила такое:
function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return Promise.all(search.map(function(val, i) {
                    /*console.log(search.length);*/
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        var $ = cheerio.load(body);
                        var txt = $('locator1').text().replace(/\s+/g," ").trim();
                        var doc = $(locator2').text().trim();
                        /*console.log(txt);*/
                        return assert.notEqual(txt, '', "не найдены: "+ doc);
                    });
                }));
            });

        }

        return checkSpec();

Теперь он хотя бы проверяет все нормально и степ фейлится, когда проверка не проходит. Проблема в том, что когда проверка падает - остальные проверки все равно проходят до конца (если не убирать вывод на консоль текста - видно, что после падения продолжает выводиться текст следующих проверок). Как сделать так, чтобы после фейла проверки прекращать остальные проверки? Пробовала вставлять if (condition) {return}, но не помогает, может тоже не туда вставляла.
  • Вопрос задан
  • 324 просмотра
Пригласить эксперта
Ответы на вопрос 3
vitali1995
@vitali1995
Нужно обернуть возвращаемые в цикле промисы в массив и в конце вернуть Promise.all(массив)

Это действие запускает ожидание выполнения всех промисов в массиве. Возвращается также промис, у которого можно вызвать
.then(...)
.catch(...)

А вообще предлагаю обратить внимание на нововведение: async/await - с ними жизнь становится в разы проще.
Ответ написан
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
forEach всегда возвращает undefined, нужен map
Чтоб дождаться выполнения всех промисов в массиве используйте Promise.all
итого:
function checkSpec() {
            return driver.executeScript("var search = []; if (typeof xmlDataSpeclist !== 'undefined') {" +
                                            "$.each(xmlDataSpeclist, function (key, item) {" +
                                                "search.push(" +
                                                "'http://domain/?spec='" + " + item.id" +
                                                ");" +
                                            "});" +
                                        "};" +
                                        "return search;"
            ).then((search) => {
                return Promise.all(search.map(function(val, i) {
                    console.log(search.length); //debug printing
                    return new Promise((resolve, reject) => {
                        request(search[i], function(error, response, body){
                            if (error) {
                                reject(error);
                            }
                            resolve(body);
                        });
                    }).then((body) => {
                        console.log(body);
                        assert.include(body, 'class="someClass"');
                    });
                }));
            });

        }

        return checkSpec();
Ответ написан
AMar4enko
@AMar4enko
var executeSequence = function(promiseFn, values, acc) {
  if (!values.length) return Promise.resolve(acc);
  var promise = promiseFn(values.shift());
  acc = acc || [];
  return promise.then(function(result) { 
    acc.push(result);
    return executeSequence(promiseFn, values, acc);
  });
};

var requestUrl = function(url) {
return new Promise((resolve, reject) => {
 request(url, function(error, response, body){
    if (error) {
       reject(error);
    }
     resolve(body);
});  
}

executeSequence(requestUrl, ['http://google.com', ...])
  .then(function(response) { 
    // response это массив из body для каждого из url по порядку
  })
  .catch(function(reason) {
    
  });


https://github.com/joliss/promise-map-series
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы