如何从一个承诺到另一个承诺获取更多数据?

时间:2020-02-19 06:17:24

标签: javascript node.js promise

我有一个承诺依赖于另一个承诺的返回值。我已经成功地将该值传递给第二个承诺,但是我想以某种方式进入第二个承诺的第一个承诺中创建了其他数据。

这是我的代码:

const getAlbumInfo = async (album, artist) => {
        let hostname = 'http://www.musicbrainz.org';
        let path = `/ws/2/release-group/?query=release:${album}%20AND%20artist:${artist}&fmt=json`;
        let res = await fetch(hostname + path);
        return res.json();
};


const getAlbumArt = async (albumInfo) => {
    let res = await fetch(`${albumInfo.url}`);
    return res.json();
};    


let artist = '', album = '';

getAlbumInfo(album, artist)
    .then((res) => {
        const metadata = {
            album: res['album'],
            artist: res['artist'],
            url: res['url']
        };

        return getAlbumArt(metadata);
    })
    .then((res) => {
        console.log(res);  // prints result from getAlbumArt

        // I also need the contents of metadata here
    })
    .catch(e => { console.error(e); });

因此,我在第一个承诺中获得了专辑元数据,其中包括一个URL,然后在该URL上运行访存,这将返回第二个承诺。问题是我需要在第二个承诺中访问专辑元数据。

由于我正在将元数据返回/传递给第二个承诺,因此我尝试在Object.assign()内使用getAlbumArt()来组合元数据和获取结果,但这似乎不起作用。

4 个答案:

答案 0 :(得分:1)

执行此操作的方法有多种,您可以使用await

const getAlbumInfo = async(album, artist) => {
  let hostname = 'http://www.musicbrainz.org';
  let path = `/ws/2/release-group/?query=release:${album}%20AND%20artist:${artist}&fmt=json`;
  let res = await fetch(hostname + path);
  return res.json();
};


const getAlbumArt = async(albumInfo) => {
  let res = await fetch(`${albumInfo.url}`);
  return res.json();
};


let artist = '',
  album = '';

const getAll = async() => {
  const res1 = await getAlbumInfo(album, artist);
  const metadata = {
    album: res['album'],
    artist: res['artist'],
    url: res['url']
  };
  const res2 = await getAlbumArt(metadata);

  // here you have access to both responses (res1 and res2) and the created metadata object.
}

如果使用此功能,则应将呼叫包装在try..catch..中。

另一个选择是将第二个承诺中的元数据与响应一起传递:

const getAlbumInfo = async(album, artist) => {
  let hostname = 'http://www.musicbrainz.org';
  let path = `/ws/2/release-group/?query=release:${album}%20AND%20artist:${artist}&fmt=json`;
  let res = await fetch(hostname + path);
  return res.json();
};


const getAlbumArt = async(albumInfo) => {
  let res = await fetch(`${albumInfo.url}`);
  res = await res.json();
  return {
    res,
    albumInfo
  };
};


let artist = '',
  album = '';

getAlbumInfo(album, artist)
  .then((res) => {
    const metadata = {
      album: res['album'],
      artist: res['artist'],
      url: res['url']
    };

    return getAlbumArt(metadata);
  })
  .then((o) => {
    console.log(o.res, o.albumInfo);
  })
  .catch(e => {
    console.error(e);
  });

第三个选择是在第一个promise的回调函数中解析第二个promise:

getAlbumInfo(album, artist)
  .then((res) => {
    const metadata = {
      album: res['album'],
      artist: res['artist'],
      url: res['url']
    };

    getAlbumArt(metadata)
      .then(res2 => {
        // here you can access res, res2 and metadata
      })
      .catch(..);
  })
  .catch(..);

答案 1 :(得分:1)

由于您可以使用async/await,因此我们也可以使用此方法解决问题。最好使用async/await而不是与Promise保持一致。

要做到这一点,我们需要IIFE

(async () => { // define IIFE
  try { // try-catch to ensure error is catched
    const res = await getAlbumInfo(album, artist);

    const metadata = {
      album: res["album"],
      artist: res["artist"],
      url: res["url"]
    };

    const res2 = await getAlbumArt(metadata);

    console.log(res2);
    console.log(metadata);

  } catch (error) {
    console.error(error);
  }
})();

希望有帮助

答案 2 :(得分:1)

await获得第二个承诺,然后将二者都返回到下一个.then块。将deconstruct用于更简单的用例:

getAlbumInfo(album, artist)
    .then(async ({album, artist, url}) => {
        const metadata = {album, artist, url};
        const arts = await getAlbumArt(metadata);

        return {arts, metadata};
    })
    .then(({arts, metadata}) => {
        // You have both here 
    })
    .catch(console.log);

或者,这整个动作可以在async函数内部:

const getAlbum = async (album, artist) => {
  const info = await getAlbumInfo(album, artist);
  const metadata = {
    album: info.album,
    artist: info.artist,
    url: info.url,
  };
  const arts = await getAlbumArt(metadata);

  // everything is available;
};

答案 3 :(得分:0)

然后您可以在内部promise中使用,并在那里返回您想要的任何格式的数据。

getAlbumInfo(album, artist)
.then((res) => {
    const metadata = {
        album: res['album'],
        artist: res['artist'],
        url: res['url']
    };

    return getAlbumArt(metadata).then(responseArt => {
       return {
           innerPromise: responseArt,
           outerPromise: metadata
       };
    });
})
.then((res) => {
    console.log(res);  // Now u have both here

    // I also need the contents of metadata here
})
.catch(e => { console.error(e); });