R
R
rundll322022-02-07 13:41:43
JavaScript
rundll32, 2022-02-07 13:41:43

Problem with nested promises?

I need to take information from api and output to render. The first promise receives dialogs, and the nested promise pulls additional data from the api for each dialog in a loop. All this is inside componentDidMount, but as a result, the cards are not updated, and the data, judging by the screen, does not have time to load.

componentDidMount() {
    // first request
    fetch(`${this.WebApiHost}/api/dialogs/get/${this.CurrentContactId}`)
    .then(function(res) {
      return res.json();
    })
    .then((json) => {
      if (!json || json.error == true) {
        console.log("error");
      } else {
        // first request is ok!
        this.state.Dialogs = [];
        // for each dialog
        json.dialogs.map((v) => {
          let dialogId = v.dialogId;
          // second request
          fetch(`${this.WebApiHost}/api/qwe/dialogs/${dialogId}/${this.My_Token}`)
          .then((res) => {
            let jsonRes = res.json();
            console.log(jsonRes);
            return jsonRes;
          })
          // second request is ok
          .then((json2) => {
            let data = json2.data;
            let msgDate = data == null ? "" : data.last_message.created;
            let msgText = data == null ? "" : data.last_message.text;
            this.state.Dialogs.push({dialogId:v.dialogId, from:v.transportName, date:msgDate, msg:msgText});
          })
          .catch((err) => {
            this.setState({IsLoading:false, Error:err});
          });
        });
      }
    }).then(() => {
      console.log("end");
      console.log(this.state.dialogs);
      this.setState({IsLoading:false});
    })
    .catch((err) => {
      this.setState({IsLoading:false, Error:err});
    });
  }

6200f727eeb93152896691.png

Answer the question

In order to leave comments, you need to log in

1 answer(s)
G
GrayHorse, 2022-02-07
@GrayHorse

You need to wait until all fetch().then().then(), collecting them in an array.

const promises /* !!! */ =  json.dialogs.map((v) => {
    let dialogId = v.dialogId;
    return /* !!! */ fetch(`${this.WebApiHost}/api/qwe/dialogs/${dialogId}/${this.My_Token}`)
    // ....
});
await Promise.allSettled(promises);

And it is better to rewrite to async/ awaitand not use asynchronous functions in map/ forEach:
try {
    const resp = await fetch("");
    const json = await resp.json();
    if (!json || json.error === true) {
        console.log("error");
    }

    async function handleDialog(dialog) {
        try {
            const resp = await fetch("");
            const json = await resp.json();
            // ...
        } catch (e) {
            // ...
        }
    }

    const concurrently = false;
    if (concurrently) {
        // [Way 1] Run one by one ---------
        for (const dialog of []) {
            await handleDialog(dialog);
        }
    } else {
        // [Way 2] Run all concurrently ---
        const promises = [];
        for (const dialog of []) {
            promises.push(handleDialog(dialog));
        }
        await Promise.allSettled(promises);
    }
    // The best way: concurrently with limitation
    // @see https://qna.habr.com/q/1105356#answer_2098042

    // ...
} catch (e) {
    // ...
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question