Я видел несколько сообщений, посвященных похожим вопросам цепочки, но я пытаюсь понять, что мне конкретно не хватает.

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

export const FetchUserSync = () => {
    return Promise.all([
        fetchUsers(),
        fetchPosts()
    ]).then(([user, posts]) => {
        return { user, posts };
    });
    
    function fetchUsers()...

    function fetchPosts()...
}

Когда я его вызываю, данные возвращаются и устанавливаются значения состояния.

useEffect(() => {
    dataPromise.then(data => {
        setUser(data.user);
        setPosts(data.posts);
    });

При попытке изменить первый код, чтобы второй вызов ждал завершения первого, я получаю результаты в функции (console.log или установка debbugger показывает заполненные объекты для пользователя и сообщения существуют), но useEffect's вызывающая функция показывает, что результат не определен.

export const FetchUserSync = () => {
    return Promise.all([fetchUsers()])
        .then(([user]) => {
            Promise.all([user, fetchPosts()]) 
                .then(([user, posts]) => {
                    return { user, posts }
                })
        });
        
        function fetchUsers()...
    
        function fetchPosts()...
    }

Любые предложения о том, как заставить вторую идею работать, или мне просто отказаться от нее и пойти с одним из других ответов?

0
John Spiegel 30 Апр 2020 в 21:40
Работает ли явная цепочка для вас? Нравится fetchUsers().then(user => fetchPosts(user)).then((posts) => console.log(posts))
 – 
vitkarpov
30 Апр 2020 в 21:46
Спасибо, но лом — это распространенная в США идиоматика, обозначающая выбрасывание идеи.
 – 
John Spiegel
20 Мар 2021 в 03:58

1 ответ

В этом случае вы не захотите использовать Promise.all.

Поскольку и fetchUsers, и fetchPosts уже возвращают промисы, обертывание единичных вызовов промисами для fetchUser и fetchPosts является антишаблоном.

Кроме того, рассмотрите возможность использования async/await, так как они избегают глубоко вложенных цепочек данных.

Вот что можно было сделать:

export const FetchUserSync = async () => {
  const users = await fetchUsers();
  const posts = await fetchPosts();

  function fetchUsers() { ... }
  function fetchPosts() { ... }

  return { users, posts }
}

Код будет запрашивать пользователей, а затем, как только пользователи будут получены, он сделает еще один вызов для сообщений.

Рекомендуем прочитать больше об async/await: https://developer. mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

1
Kevin Bai 30 Апр 2020 в 21:49
Ваш код будет ждать, пока fetchUsers не будет разрешен, а затем сделает fetchPosts. Но те выбирают независимые So Promise.all быстрее. Например, если fetchUsers разрешается за время a мс, а fetchPosts разрешается за время b мс, async/await будет разрешен за a+b мс. В то же время Promise.all будет разрешено Math.max(a,b) мс.
 – 
Kirill Skomarovskiy
30 Апр 2020 в 22:08
Да, вы правы в своем случае, но я почти уверен, что OP хочет этого эффекта: «Попытка изменить первый код, поэтому второй вызов будет ждать завершения первого». В некоторых случаях вам понадобится результат первого вызова, чтобы сделать второй вызов. Текущий код OP извлекает код одновременно, но я думаю, что он пытается дождаться завершения первого вызова.
 – 
Kevin Bai
30 Апр 2020 в 22:13
Спасибо, возможно, я упростил свой пример, но вы его прибили. Я хочу добраться до точки, где второй вызов опирается на данные из результатов первого.
 – 
John Spiegel
30 Апр 2020 в 23:25
Я даже не могу оценить, сколько (часто запутанных) неудачных попыток у меня было! Спасибо еще раз.
 – 
John Spiegel
1 Май 2020 в 00:03