如何在promise之间异步传递数据?

How to pass data between promise asynchronously?

我想从后端获取几个数据并在加载时最后处理它们。现在,当这段代码运行时,data1 和 data2 是未定义的。我想等他们,但我不知道如何保持我的代码干净。我不确定 Promise.all() 是否适合这里,因为我需要专门保存 data1 和 data2 的值,而且我无法编写通用代码来解析 Promise.all()。

return new Promise( (resolve,reject) => {
 let data1;
 let data2;

 let url1 = "http://fakeapi.com/getData1";
 fetch(url1)
 .then(res => res.json())
 .then(data => data1SpecificAction())
 .then(data => data1 = data)
 .catch("cannot fetch data1")

 let url2 = "http://fakeapi.com/getData2";
 fetch(url2)
 .then(res => res.json())
 .then(data => data2 = data)
 .catch("cannot fetch data2")

 if(data1 && data2) {
  resolve()
 }
 else {
  reject()
 }
}

如何修复此代码段?

解决方案是将我的具体操作放入另一个承诺中并使用 promise.all

return new Promise( (resolve,reject) => {
 let data1;
 let data2;

 let promise1 = new Promise( (resolve,reject) => {
  let url1 = "http://fakeapi.com/getData1";
  fetch(url1)
  .then(res => res.json())
  .then(data => data1SpecificAction())
  .then(data => { 
   data1 = data;
   resolve()
   }
  .catch(()=>reject("cannot fetch data1"))
 })

 let promise 2 = new Promise( (resolve,reject) => {
  let url2 = "http://fakeapi.com/getData2";
  fetch(url2)
  .then(res => res.json())
  .then(data => { 
   data2 = data;
   resolve()
   }
  )
  .catch(()=>reject("cannot fetch data2"))
 })

 Promise.all([promise1,promise2])
 .then(
  () => {
   if(data1 && data2) {
    resolve()
   }
   else {
     reject()
   }
  }
 )

here 是 link 解释如何在 promise 之间传递数据。

您的问题或答案中不需要太多内容。你可以这样做:

const url1 = "http://fakeapi.com/getData1";
const url2 = "http://fakeapi.com/getData2";
return Promise.all([
    fetch(url1).then(res => res.json()).then(data1SpecificAction), 
    fetch(url2).then(res => res.json())
]).then([data1, data2] => {
    if (data1 && data2) return;         // resolve
    // reject with appropriate error
    let msg = data1 ? "missing data2" : "missing data1";
    throw new Error(msg);
});

您的问题和答案中不需要做的事情:

  1. 不要将现有的承诺包装在另一个手动创建的承诺中。这被认为是一种反模式,因为根本不需要手动创建的承诺。你可以 return 你已经拥有的承诺。
  2. 不要将 .then() 结果分配给更高范围的变量。虽然偶尔会有这样的原因,但这不是其中之一,通常是您做错事的警告信号。

我发现 fetch() 界面有一些令人烦恼的地方,我发现这些界面经常受益于辅助函数(例如 404 状态解析,而不是拒绝):

function fetchJson(...args) {
    return fetch(...args).then(res => {
        if (!res.ok) throw new Error(`Got ${res.status} status`);
        return res.json();
    });
}

const url1 = "http://fakeapi.com/getData1";
const url2 = "http://fakeapi.com/getData2";
return Promise.all([
    fetchJson(url1).then(data1SpecificAction), 
    fetchJson(url2)
]).then([data1, data2] => {
    if (data1 && data2) return;         // resolve
    // reject with appropriate error
    let msg = data1 ? "missing data2" : "missing data1";
    throw new Error(msg);
});

而且,在您想要拒绝结果为假的特定情况下,您甚至可以这样做:

function fetchJsonCheck(...args) {
    return fetch(...args).then(res => {
        if (!res.ok) throw new Error(`Got ${res.status} status`);
        return res.json();
    }).then(result => {
        if (!result) throw new Error("empty result");
        return result;
    });
}

const url1 = "http://fakeapi.com/getData1";
const url2 = "http://fakeapi.com/getData2";
return Promise.all([
    fetchJsonCheck(url1).then(data1SpecificAction), 
    fetchJsonCheck(url2)
]);