Прерывание вложенных запросов на выборку при размонтировании компонента - PullRequest
2 голосов
/ 27 апреля 2020

Следующая функция, когда используется, выбирает и возвращает массив до 50 комментариев одного сообщения. Сначала он выбирает одну запись по идентификатору, и у этого объекта записи есть массив идентификаторов комментариев, которые он будет получать.

Моя цель состоит в том, чтобы досрочно прервать эту задачу в моем компоненте класса React, используя componentWillUnmount, вызов abort по сигналу на экземпляре класса. Сигнал передается как abortSignal.

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

const fetchComments = async (type, abortSignal) => {
    const res = await fetch(endpoints[`${type}Stories`]);
    const post = await res.json();
    return Promise.all(post.slice(0, 50).map(async id => {
        const url = endpoints.singleStory.replace('[id]', id);
        const comment = await fetch(url);
        return comment.json();
    }));
}

1 Ответ

2 голосов
/ 27 апреля 2020

Я не вижу причин, по которым вы не можете повторно использовать abortSignal во всех fetch вызовах. Вы, вероятно, также захотите проверить его флаг aborted после await ing, чтобы заранее внести залог:

const fetchComments = async (type, signal) => {
    const res = await fetch(endpoints[`${type}Stories`], {signal});
    if (signal.aborted) {
        return; // Or whatever
    }
    if (!res.ok) {
        throw new Error("HTTP error " + res.status);
    }
    const post = await res.json();
    if (signal.aborted) {
        return; // Or whatever
    }
    return Promise.all(post.slice(0, 50).map(async id => {
        // Probably not much point to checking `signal.aborted` here, you *just* checked it above
        const url = endpoints.singleStory.replace('[id]', id);
        const comment = await fetch(url, {signal});
        if (!comment.ok) {
            throw new Error("HTTP error " + comment.status);
        }
        return comment.json();
    }));
}

Два примечания по этому поводу:

  1. Я изменил abortSignal на signal чтобы я мог использовать сокращенную запись свойства при передаче его на fetch, потому что я ленивый. : -)
  2. Ваш код становится жертвой fetch ножка - вам нужно проверить успешность HTTP, он отклоняется только в сеть ошибка, а не HTTP ошибка. Я вставил чеки выше.

Примечание: Если вы можете изменить API, я настоятельно рекомендую сделать возможным запрос 50 комментариев как части из первоначального fetch, или, по крайней мере, чтобы иметь возможность запросить пакет комментариев, а не загружать каждый комментарий индивидуально с его собственным HTTP-запросом (хотя HTTP / 2 очень помогает).

...