Используйте асинхронное / ожидание с выборкой и foreach

#javascript

Вопрос:

Этот код должен выполнить следующее: Выполните поиск по всем ссылкам на текущей странице и проверьте наличие нескольких ошибок. Проверка должна быть проведена до отображения результатов на странице. Поэтому я хочу заполнить массив ошибками и вернуть его после завершения всех проверок.

 interface LinkObject {
    element: HTMLAnchorElement;
    url: URL;
    checkTrigger?: HTMLButtonElement;
}

interface ErrorObject {
    element: HTMLElement;
    errors: string[];
    warnings: string[];
}


export default class LinkCheckTool {

    protected linksObjects: LinkObject[] = [];
    protected errors: ErrorObject[] = [];

    constructor() {

        document.querySelectorAll('a').forEach((linkElement) => {
            const button: HTMLButtonElement = document.createElement('button');
            button.classList.add('tb-o-linkobject__btn');
            const url: URL = new URL(linkElement.href);
            if (url) {
                linkElement.appendChild(button);
                this.linksObjects.push({
                    element: linkElement,
                    url: url,
                    checkTrigger: button
                })
            }
        })

        const errors = this.fetchErrors();
        console.log(errors); // results in an empty array, so need to use async / await here
    }

    protected fetchErrors() {
        const errors = [];
        this.linksObjects.forEach((linkObject) => {
            if (linkObject.url.protocol !== 'javascript:') {
                fetch(linkObject.url.href)
                  .then((response) => (response))
                  .then((response) => {
                      if (!response.ok) {
                          // push to errors here
                      }
                  })
                  .catch((error) => {
                      // push to errors here
                  })
            }
        })
    }
}
 

В этом случае вывод ошибок консоли, конечно, возвращает пустой массив. Как я могу использовать async / await и вернуть обещание здесь?

Комментарии:

1. Кроме того, после преобразования ошибок выборки в асинхронные конструкторы не могут быть асинхронными, поэтому вам также нужно будет сделать -> this.fetchErrors().then(....

2. @MrMythical карта будет работать, но .forEach(async это не поможет.

Ответ №1:

Функция fetchErrors здесь не асинхронна, потому что она не возвращается Promise . И поскольку вы пытаетесь вызвать функцию в constructor async/await синтаксисе, она на самом деле не будет работать в этом контексте.

Вместо этого вам нужно использовать Promise обратный вызов здесь. Вы можете применить этот Promise.allSettled метод. Это поможет вам подождать, пока ваши запросы не будут решены, а затем вы сможете обрабатывать ответы один за другим.

 constructor() {
    // ...
    
    const errors = [];

    this.fetchErrors().then(results => {
        results.forEach(result => {
            if (result.status === "rejected") {
                errors.push(result.value)                
            }
        })

        console.log(errors); // will print you list of errors
    });
    
}

protected fetchErrors() {
    const requests = this.linksObjects
        .filter(linkObject => linkObject.url.protocol !== 'javascript:')
        .map((linkObject) => fetch(linkObject.url.href))

    return Promise.allSettled(requests);
}
 

Комментарии:

1. Отлично, спасибо. Ты сделал мой день лучше…