Javascript使用promise函数遍历数组,以随机顺序返回值

我的代码旨在循环运动队ID的数组,以使用它们从API编译各种信息,然后将HTML添加到我的页面以显示每个队最近完成的比赛。它正在运行并且看起来很棒,除了:每次刷新时,结果都会以随机顺序出现在我的页面上。我认为这与循环快速移至下一个迭代有关,而服务器的响应会在随机时间返回。我希望结果首先是“爱国者”,然后是“ Steelers”,但结果是随机的,爱国者队几乎从来没有出现过。

此外,我对JS还是很陌生,所以我敢肯定我可以做很多事情来使它变得更好,所以在此先感谢您!

//Define the teams I want scores from and their API reference numbers.
let teams = new Map();
teams.set("Patriots",134920);
teams.set("Steelers",134925);
teams.set("Bruins",134830);
teams.set("Penguins",134844);
teams.set("Celtics",134860);
teams.set("Red Sox",135252);
teams.set("Huskers",136923);

let teamArr = Array.from(teams.values());
for (i = 0; i < teamArr.length; i++) {
    console.log(teamArr[i]);
}

//Get the team data so that we can pull the logo image.
async function getTeamData(teamID) {
    let result = await fetch(`https://www.thesportsdb.com/api/v1/json/1/lookupteam.php?id=${teamID}`)
    let teamData = await result.json();
    return teamData.teams[0];
}

//Get the info for the teams last game.
async function getLastGame(teamID) {
    let result = await fetch(`https://www.thesportsdb.com/api/v1/json/1/eventslast.php?id=${teamID}`)
    const lastGames = await result.json();
    const lastGame = lastGames.results[0];
    return lastGame;
};

//Populate the final scores with new HTML after pulling all the info from the API.
for (let i = 0; i < teamArr.length; i++) {
    let homeTeam,awayTeam,homeTeamData,awayTeamData,homeTeamLogo,gameDay;
    getLastGame(teamArr[i])
    .then(lastGame => {
        gameDay = lastGame.dateEvent;
        homeTeam = {
            name: lastGame.strHomeTeam,id: lastGame.idHomeTeam,score: lastGame.intHomeScore,};
        awayTeam = {
            name: lastGame.strAwayTeam,id: lastGame.idAwayTeam,score: lastGame.intAwayScore
        }; //This is all the info we need except for the team icons.
    }).then(result => {
        homeTeamData = getTeamData(homeTeam.id)
        return homeTeamData; 
    }).then(result => {
        homeTeam.logo = result.strTeamBadge;
    }).then(() => {
        awayTeamData = getTeamData(awayTeam.id)
        return awayTeamData;
    }).then(result => {
        awayTeam.logo = result.strTeamBadge; //After getting who was home and who was away,these let us pull and put the right icon in the table.
    }).then(() => {
        let html = `    <tr>
                            <th><img src="%awayImg%" alt="Away" id="${i}-away" class="team-logo"></th>
                            <th><div class="at-vs">@</div></th>
                            <th><img src="%homeImg" alt="Home" id="${i}-home" class="team-logo"></th>
                        </tr>
                        <tr>
                            <th><div class="away-score">%awayScore%</div></th>
                            <th><div class="gameday">%gameDay%</div></th>
                            <th><div class="home-score">%homeScore%</div></th>
                        </tr>`;
        let newhtml = html.replace(`%awayImg%`,awayTeam.logo + "/preview");
        newhtml = newhtml.replace(`%homeImg`,homeTeam.logo + "/preview");
        newhtml = newhtml.replace(`%awayScore%`,awayTeam.score);
        newhtml = newhtml.replace(`%gameDay%`,gameDay);
        newhtml = newhtml.replace(`%homeScore%`,homeTeam.score);

        document.querySelector(`.past-games-table`).insertAdjacentHTML(`beforeend`,newhtml);

    })
};
norika1117 回答:Javascript使用promise函数遍历数组,以随机顺序返回值

您正在混淆实现相同目标的两种模式。这是用async await

重构的代码
//Define the teams I want scores from and their API reference numbers.
let teams = new Map();
teams.set("Patriots",134920);
teams.set("Steelers",134925);
teams.set("Bruins",134830);
teams.set("Penguins",134844);
teams.set("Celtics",134860);
teams.set("Red Sox",135252);
teams.set("Huskers",136923);

let teamArr = Array.from(teams.values());
for (i = 0; i < teamArr.length; i++) {
    console.log(teamArr[i]);
}

//Get the team data so that we can pull the logo image.
async function getTeamData(teamID) {
    let result = await fetch(`https://www.thesportsdb.com/api/v1/json/1/lookupteam.php?id=${teamID}`)
    let teamData = await result.json();
    return teamData.teams[0];
}

//Get the info for the teams last game.
async function getLastGame(teamID) {
    let result = await fetch(`https://www.thesportsdb.com/api/v1/json/1/eventslast.php?id=${teamID}`)
    const lastGames = await result.json();
    const lastGame = lastGames.results[0];
    return lastGame;
};

//Populate the final scores with new HTML after pulling all the info from the API.
for (let i = 0; i < teamArr.length; i++) {
    let homeTeam,awayTeam,homeTeamData,awayTeamData,homeTeamLogo,gameDay;
    const lastGame = await getLastGame(teamArr[i]);
    gameDay = lastGame.dateEvent;
    homeTeam = {
        name: lastGame.strHomeTeam,id: lastGame.idHomeTeam,score: lastGame.intHomeScore,};
    awayTeam = {
        name: lastGame.strAwayTeam,id: lastGame.idAwayTeam,score: lastGame.intAwayScore
    }; //This is all the info we need except for the team icons.
    homeTeamData = await getTeamData(homeTeam.id);
    homeTeam.logo = homeTeamData.strTeamBadge;
    awayTeamData = await getTeamData(awayTeam.id);
    awayTeam.logo = awayTeamData.strTeamBadge; //After getting who was home and who was away,these let us pull and put the right icon in the table.
    let html = `    <tr>
                        <th><img src="%awayImg%" alt="Away" id="${i}-away" class="team-logo"></th>
                        <th><div class="at-vs">@</div></th>
                        <th><img src="%homeImg" alt="Home" id="${i}-home" class="team-logo"></th>
                    </tr>
                    <tr>
                        <th><div class="away-score">%awayScore%</div></th>
                        <th><div class="gameday">%gameDay%</div></th>
                        <th><div class="home-score">%homeScore%</div></th>
                    </tr>`;
    let newhtml = html.replace(`%awayImg%`,awayTeam.logo + "/preview");
    newhtml = newhtml.replace(`%homeImg`,homeTeam.logo + "/preview");
    newhtml = newhtml.replace(`%awayScore%`,awayTeam.score);
    newhtml = newhtml.replace(`%gameDay%`,gameDay);
    newhtml = newhtml.replace(`%homeScore%`,homeTeam.score);

    document.querySelector(`.past-games-table`).insertAdjacentHTML(`beforeend`,newhtml);

};
,

您可以在async函数中做的一件事是await解决Promise。在for循环中,这意味着直到上一次迭代解决后,您才能继续执行循环。这是一个简单的例子。如果将所有提取汇总到一个数组(例如[getLastGame(teamArr[0]),getLastGame(teamArr[1]),getLastGame(teamArr[2]),etc.])中,然后在每个元素上使用await遍历该数组,则可能会得到类似的结果。

const timed = (id) => new Promise(res => {
  setTimeout(() => res(id),Math.random() * 2000);
})

const func = async () => {
  const promises = [timed(1),timed(2),timed(3),timed(4)];
  for (let promise of promises) {
    const returned = await promise;
    console.log(returned);
  }
}

func();

您可以考虑的另一种方法是,再次汇总所有的诺言,然后使用Promise.all等待所有诺言的解决,然后在所有数据到达时执行一些操作:

Promise.all([getLastGame(teamArr[0]),getLastGame(teamArr[1],etc.)])
  .then(all => {
    // the `all` variable will contain an array of all resolved promises
  })
,

您似乎想要的是发出并发请求以获取数据,但无论它们何时到达,都仍然以一定顺序显示它们。

现在,您将一个接一个地发出所有请求,并在获得请求时显示结果。这意味着显示结果的顺序是不可预测的,任何先前的请求都可以在随后的任何请求之前完成,并且您的数据将不按顺序显示。

尝试多次运行此代码段,显示顺序不可预测:

注意,在下面的示例中,我使用了一些虚假函数来表示对数据的请求并显示它。 fakeRequest是一个函数,可以表示承诺链中除最后一个函数以外的所有函数(用于获取和建立团队数据的所有逻辑),而fakeDisplay是一个函数,可以表示您的承诺的最后一部分附加HTML并显示数据的链。

const fakeRequest = n => new Promise(
  resolve => setTimeout(() => {
    console.log(`requesting ${n}`);
    resolve(n);
  },Math.random() * 1000)
);

const fakeDisplay = n => console.log(`displaying ${n}`);

// all requests are made one after the other
// and as soon as a request is done,we display
// the data,no matter which request that is
for (let i = 0; i < 3; i++) {
  fakeRequest(i).then(fakeDisplay);
}

这里的主要问题是您的显示逻辑与获取团队数据的逻辑联系在一起。拆分此行为将使您可以通过多种方式解决问题。

解决此问题的一种方法是在上一个请求+显示操作完成之前才发出请求(并且不显示数据):

const fn = async () => {
  // note: using await is only valid in an async function
  const fakeRequest = n => new Promise(
    resolve => setTimeout(() => {
      console.log(`requesting ${n}`);
      resolve(n);
    },Math.random() * 1000)
  );

  const fakeDisplay = n => console.log(`displaying ${n}`);

  // make each request and wait for it to finish
  // then display the result and start next request 
  for (let i = 0; i < 3; i++) {
    const item = await fakeRequest(i);
    fakeDisplay(item);
  }
}

fn();

减轻这种情况的另一种方法是等到所有请求完成后再一次显示所有结果(使用Promise.all):

const fakeRequest = n => new Promise(
  resolve => setTimeout(() => {
    console.log(`requesting ${n}`);
    resolve(n);
  },Math.random() * 1000)
);

const fakeDisplay = n => console.log(`displaying ${n}`);

// make the requests one after the other
// and save all the promises in an array
const promises = []
for (let i = 0; i < 3; i++) {
  promises.push(fakeRequest(i));
}

// then use a built-in utility Promise.all to
// display all the results once they all arrive
Promise.all(promises)
  .then(results => {
    for (const item of results) {
      fakeDisplay(item);
    }
  })

主要问题是,在完成所有请求之前,您的用户界面将不会显示任何内容,这可能会花费一些时间,并且可能不是理想的体验。

如果您几乎同时发出所有请求,但仍按正确的顺序显示结果,则也许是UX的最佳选择。

const fn = async () => {
  const fakeRequest = n => new Promise(
    resolve => setTimeout(() => {
      console.log(`requesting ${n}`);
      resolve(n);
    },Math.random() * 1000)
  );

  const fakeDisplay = n => console.log(`displaying ${n}`);

  // make the requests one after the other
  // and save all the promises in an array
  const promises = []
  for (let i = 0; i < 3; i++) {
    promises.push(fakeRequest(i));
  }

  // loop through the promises and resolve each
  // one and display the data
  for await (const item of promises) {
    fakeDisplay(item);
  }
}

fn();

本文链接:https://www.f2er.com/3039757.html

大家都在问