Промис не дожидается ответа из асинхронной функции

Я новичок в JS и еще учусь. Решил попробовать написать расширение для Chrome.

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

const linkedInSearchElement = (keyWords) => {

            return new Promise((resolve, reject) => {
                chrome.tabs.create({
                    url: `https://www.linkedin.com/sales/search/company?keywords=${keyWords}&page=1&searchSessionId=0ehP5LShQGivgqjzo9LqjQ%3D%3D`
                }, (tab) => {
                    resolve(tab.id);
                });
            }).then((tabId) => {
                return new Promise((resolve, reject) => {
                    chrome.tabs.executeScript(tabId, {
                        'code': 'function linksWineSearch (){let wineLinks = []; const wineCompNames = document.getElementsByClassName("result-lockup__name"); for (let wineCycleCount = 0; wineCycleCount <wineCompNames.length; wineCycleCount++) {wineLinks[wineCycleCount] = wineCompNames[0].children[0].href} console.log(wineLinks); return wineLinks; } linksWineSearch(); '
                    }, (wineLinks) => {
                        resolve([wineLinks, tabId]);
                    });
                })
            }).then((linksAndId) => {
                return new Promise((resolve, reject) => {
                    chrome.tabs.remove(linksAndId[1], () => {

                        resolve(linksAndId[0]);
                    });
                })

            }).catch(error => console.log(error));

        };

        const linkedInGeneralSearch = (readyNames) => {
            const compNames = [...readyNames];
            let linkList = [];
            for (let i = 0; i < 2; i++) {
                const keyWords = compNames[i];
                console.log(linkedInSearchElement(keyWords));
                const searchElementResult = linkedInSearchElement(keyWords);
                linkList = [...searchElementResult];
            }
            return linkList;
        }

Но почему-то после 'chrome.tabs.create' все '.then' пропускаются и функция 'linkedInSearchElement' выполняется заново и так далее. И только после всех итераций по очереди начинают выполнятся все '.then'.

Почему все .then не выполняются по порядку, функция запускается заново до окончания предыдущей?

P.S. Я старался изучить асинхронное программирование в JS, но тут не могу разобраться)) Заранее спасибо за ответы!


Ответы (1 шт):

Автор решения: Владимир Михайлов

Все дело в том что асинхронная функция возвращает обещание (Promise) - асинхронный код, который в свою очередь уже имеет свой жизненный цикл, и два статуса завершения работы: "успех" (then) или "провал" (catch).

Далее, тут: for (let i = 0; i < 2; i++) ты вызываешь синхронный цикл, который запускает 2 раза подряд linkedInSearchElement. То есть ты имеешь: в одном потоке вызвал асинхронную функцию и тут же работаешь с данными, которые вообще не в курсе что там с ними происходит внутри асинхронного блока.

Обязательно прочитай что такое async/await если хочешь дальше учиться писать грамотный асинхронный код.

Идея сделать так:

for (let i = 0; i < 2; i++) {
   const keyWords = compNames[i];
   const searchElementResult = [] 
   linkList = [...await linkedInSearchElement(keyWords)];
}

То есть ты "ждешь" пока закончится твой асинхронный метод linkedInSearchElement, и берешь его значение и помещаешь в массив.

Но на самом деле, если сделаешь как я написал, это не сработает. Потому что await работает только внутри async (асинхронных функции).

Итоговый вариант должен выглядеть как то так:

async function linkedInSearchElement(keyWords) {
    try {
        const tabId = await chrome.tabs.create({url: ''};
        const linksAndId = await chrome.tabs.executeScript(tabId, { 'code': ''};
        chrome.tabs.remove(linksAndId[1]);
        return linksAndId[0];
    } catch (error) {
        console.log(error);
    } }

async function linkedInGeneralSearch(readyNames) {
    const compNames = [...readyNames];
    return await processArray(compNames); }

async function processArray(array) {
    const linkList = [];
    for (const item of array) {
        linkList.concat(await linkedInSearchElement(item));
    }
    return linkList; }

Код не запускал.

→ Ссылка