如何使用JavaScript承诺使一个函数等待另一个函数完成异步运行?

时间:2019-02-22 07:36:43

标签: javascript asynchronous promise async-await

// TODO: FIX CODE - IT IS STILL NOT WAITING FOR populateVenueIDs
// BEFORE CALLING populateFsPhotoRequestURLs
// must use async, not sync to meet assignment requirements.

let populateVenueIDs = new Promise(function(resolve, reject) {
  for (let y = 0; y < window.coffeeShopLocations().length; y++) {
    let getVenueIDFromFS = new XMLHttpRequest();
    getVenueIDFromFS.open('GET', window.fsURL[y]);
    getVenueIDFromFS.onload = function() {
      let responseFromFS = JSON.parse(getVenueIDFromFS.responseText);
      window.fsVenueID[y] = responseFromFS.response.venues[0].id;
      console.log(window.fsVenueID[y]);
    }; 
    getVenueIDFromFS.send();
  } 
  resolve("done!");
}); 

function populateFsPhotoRequestURLs() {
  for (let y = 0; y < window.coffeeShopLocations().length; y++) {
    window.fsPhotoEndpoint[y] = 'https://api.foursquare.com/v2/venues/'
      + window.fsVenueID[y] + '/photos';
    window.fsPhotoRequestURL[y] = fsPhotoEndpoint + '?' + fsPhotoParams;
    console.log(window.fsPhotoRequestURL[y]);
  } 
} 


populateVenueIDs.then(
  populateFsPhotoRequestURLs()
);

在运行populateFsPotoRequestURLs之前,它仍然不等待populateVenueID。

我还尝试了await,promise等各种变体。我已经阅读了大约15个关于这些主题的教程,但是没有一个教程足够接近我想要的。我不想使用超时(90%的教程使用了超时),因为那样会不必要地减慢应用程序的速度。我必须使用异步来满足分配要求。 请帮助我点点滴滴答应和/或等待/然后在这种情况下适用。

2 个答案:

答案 0 :(得分:3)

您的populateVenueIDs函数只是解析为完成,而无需等待onload函数被调用。如果可以的话,fetch将是一个不错的选择,因为它返回承诺,但IE不支持。

您可以做的是为循环的每次迭代创建一个Promise,并使用Promise.all(arrayOfPromises)等待所有请求。这样甚至可以并行执行所有XMLHttpRequest

示例代码:

let populateVenueIDs = new Promise(function(resolve, reject) {
    let promises = [];

    for (let y = 0; y < window.coffeeShopLocations().length; y++) {
        promises.push(new Promise(function (resolve) {
            let getVenueIDFromFS = new XMLHttpRequest();
            getVenueIDFromFS.open('GET', window.fsURL[y]);
            getVenueIDFromFS.onload = function() {
                let responseFromFS = JSON.parse(getVenueIDFromFS.responseText);
                window.fsVenueID[y] = responseFromFS.response.venues[0].id;
                console.log(window.fsVenueID[y]);
                resolve();
            };
            getVenueIDFromFS.send();
        }));

    }
    return Promise.all(promises)
        .then(function () {
            resolve('Done!');
        })
}); 

获取解决方案

正如您所说的,这是一个任务,您可能可以将ES6与asyncawait一起使用,这将是一个不错的解决方案:

async function populateVenueIDs() {

    let promises = [];

    for (let y = 0; y < window.coffeeShopLocations().length; y++) {
        promises.push(new Promise(async resolve => {
            const response = await fetch(window.fsURL[y]);
            const data = await response.json();
            window.fsVenueID[y] = data.venues[0].id;
            resolve();
        }));
    }

    await Promise.all(promises);
}

答案 1 :(得分:1)

虽然我坚信@JensV的答案正确,但我在评论中这么说,我只是想跟进使用fetch时代码的样子(我只包含了有关JensV的答案)

var promises = [];

for (let y = 0; y < window.coffeeShopLocations().length; y++) {
    promises.push(fetch(window.fsURL[y])
      .then(response => response.json())
      .then(data => {
        window.fsVenueID[y] = data.response.venues[0].id;
      }));
}

编辑:为了后代的缘故,我在詹斯(Jens)添加他的提取解决方案之前就发布了此内容:)