【问题标题】:Chaining two promises链接两个 Promise
【发布时间】:2019-03-02 00:08:30
【问题描述】:

我有两个承诺

    const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
      .then(ting => {
        console.log(ting);
        Dispatcher.dispatch({
        actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
        payload: ting.data.password
      })})
      .catch(error => {console.log(error)});

    const promise_2 = this.connection.getAllPatientData()
      .then( function(response) {
        console.log("Dispatrinc a new server call")
        console.log(response.data)
       Dispatcher.dispatch({
        actionType: Constants.CHANGE_ALL_PATIENTS,
        payload: response.data
      })})
      .catch(error => console.log(error))


      console.log("Done");
  }

第一个将一些数据发布到服务器,第二个查询数据重新下载 新列表。第二个依赖于第一个。问题是第一个承诺是在之后实现的。第二个应许首先实现。 我怎样才能将这两个承诺链接在一起 所以promise 2 等待promise 1?

【问题讨论】:

  • 在 insertPatientToDataBase 函数中调用 this.connection.getAllPatientData() 函数,这就是我们链接 http 调用的方式
  • promise_1.then( promise_1_result => promise_2()).then( promise_2_result => { ... }) 根据 promise_2 是否需要 promise_1 的结果,您可能希望将 p1 结果用作 p2 或其他东西的参数和/或将它们包装在另一个函数中。
  • 你不能链接一个promise,但是你可以链接一个创建promise的函数。

标签: javascript promise axios


【解决方案1】:

如果这两个函数不相关,但 promise_1 必须先解析以使患者存在,则您可以将 promise 创建包装在一个函数中,并且仅在 promise_1 解析时调用 promise_2 创建:

const promise_1 = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
  .then(ting => {
    console.log(ting);
    Dispatcher.dispatch({
    actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
    payload: ting.data.password
  })})
  .catch(error => {console.log(error)});

const promise_2 = () => this.connection.getAllPatientData()
  .then( function(response) {
    console.log("Dispatrinc a new server call")
    console.log(response.data)
   Dispatcher.dispatch({
    actionType: Constants.CHANGE_ALL_PATIENTS,
    payload: response.data
  })})
  .catch(error => console.log(error));

  promise_1().then( response => promise_2());

如果 promise_2 依赖于 promise_1 的结果来运行,例如,如果 promise_1 将返回患者 id 并且您需要该 id 来运行 promise_2 并且只有 promise_2 的结果必须在两者都解析后可用,那么您可以修改上面一点点传递参数:

const promise_1 = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
      .then(ting => {
        console.log(ting);
        Dispatcher.dispatch({
        actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
        payload: ting.data.password
      })})
      .catch(error => {console.log(error)});

const promise_2 = patient_id => this.connection.getAllPatientData( patient_id )
      .then( function(response) {
        console.log("Dispatrinc a new server call")
        console.log(response.data)
       Dispatcher.dispatch({
        actionType: Constants.CHANGE_ALL_PATIENTS,
        payload: response.data
      })})
      .catch(error => console.log(error));

promise_1()
  .then( patient_id => promise_2( patient_id ))
  .then( patient_data => {
    // handle patient data.
  });

您还可以将所有内容重组为更多原子函数,因此每个 Promise 都有一个特定目标,因此您可以将它们链接在一起。如果你以不同的方式嵌套结构,你甚至可以保存所有响应并在最后返回所有 fo then。

const create_patient_id = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID());

const create_patient = patient_id => Dispatcher.dispatch({
    actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
    payload: patient_id.data.password
});

const get_patients = () => this.connection.getAllPatientData();

const update_patients = patients => Dispatcher.dispatch({
    actionType: Constants.CHANGE_ALL_PATIENTS,
    payload: patients.data
})

const workflow = () => create_patient_id()
  .then( create_patient );
  .then( get_patients )
  .then( update_patients );

 workflow();

【讨论】:

  • 令人困惑。在第二个代码块中,promise_1 和 promise_2 是函数,而不是承诺。
  • 我没有选择这些名字,所以假装是get_promise_1 和get_promise_2。在我展示重命名/重构版本之前,我在第一个和第二个示例中使用了相同的名称来避免过多地混淆 OP。关键是直接创建 promise,而不使用函数,这正是 promise_2 有时在 promise_1 之前解析的原因。
  • get_promise_1 和 get_promise_2 会更好。
  • 我更喜欢为函数命名。我永远不会在生产就绪代码中编写类似 promise_1、promise_2 的东西。因此,我非常喜欢最后一个版本。
【解决方案2】:

使用then 时,您可以通过在前一个解析器中创建下一个来链接承诺:

const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
  .then(ting => {
    console.log(ting);

    Dispatcher.dispatch({
      actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
      payload: ting.data.password
    });

    return this.connection.getAllPatientData();
  })
  .then(response => {
    console.log("Dispatrinc a new server call");
    console.log(response.data);

    Dispatcher.dispatch({
      actionType: Constants.CHANGE_ALL_PATIENTS,
      payload: response.data
    });
  })
  .catch(error => {console.log(error)});

使用 async/await 这可能会更容易:

async insertAndGet() {
  try {
    const ting = await this.connection.insertPatientToDataBase(Store.getPotentialPatientID());

    console.log(ting);

    Dispatcher.dispatch({
      actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
      payload: ting.data.password
    };

    const response = await this.connection.getAllPatientData();

    console.log("Dispatrinc a new server call");
    console.log(response.data);

    Dispatcher.dispatch({
      actionType: Constants.CHANGE_ALL_PATIENTS,
      payload: response.data
    })};
  } catch (error) {
    console.log(error);
  }
}

【讨论】:

    【解决方案3】:

    您可以简单地将第二个 Promise 移动到第一个的 then 部分。 如果第一个 Promise 失败,则第二个 Promise 不会执行,如果它成功解决 - 第二个 Promise 将开始。 代码将如下所示:

    const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
      .then(ting => {
        console.log(ting);
        Dispatcher.dispatch({
          actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
          payload: ting.data.password
        });
        const promise_2 = this.connection.getAllPatientData()
          .then(response => {
            console.log("Dispatrinc a new server call");
            console.log(response.data);
            Dispatcher.dispatch({
              actionType: Constants.CHANGE_ALL_PATIENTS,
              payload: response.data
            });
        })
        .catch(console.log);
      })
      .catch(console.log);
    
      console.log("Done");
    }
    

    您还可以将Promises 的结果从一个then 链接到另一个,如下所示:

    SomePromiseFunc().then(result1 => SomeOtherPromiseFunc(result1)).then(result2=> doSmth(result2)).catch();
    

    如果您想在第二个中使用第一个Promise 的结果,或者如果catch 的逻辑对它们两者相同,这种方式可能会更容易。

    【讨论】:

    • 你可以,但你应该使用 Promise 链来代替。
    • @str 您能否提供一个示例以供将来参考?鉴于对链中第二个 then.(.. 的方法的引用不具有我需要的 this.connection 的范围,我对如何链接它感到困惑
    • @bell_pepper 我添加了Promise 与编辑链接,这是帖子中的第二个示例。
    • @bell_pepper this.connection is not a problem 如果您在 then 回调中使用箭头函数
    【解决方案4】:
    Promise1()
      .then(response => Promise2(response))
      .catch(err => {
        // do something with error
      });
    

    这会等到第一个 Promise 被解决,然后用结果调用第二个 Promise。如果您不需要它.then(() => Promise2()),您不必传递结果。如果Promise1 失败,则永远不会调用Promise2。

    注意:显然我在最初的回复中不够冗长,所以让我们更好地分解一下。

    首先,包装你的 Promise 调用,这样你就可以为每个调用提供额外的功能:

    class MyCustomClass {
      createNewPatient() { // maybe you pass it in? maybe it's always there?
        // Guessing Store is outside the class, but available
        return this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
          .then(ting => {
            console.log(ting);
            // Guessing Dispatcher and Constants are outside the class, but available
            Dispatcher.dispatch({
              actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
              payload: ting.data.password
            });
          })
          .catch(error => {console.log(error)});
      }
    
      reloadResults() {
        return this.connection.getAllPatientData()
          .then( function(response) {
            console.log("Dispatrinc a new server call")
            console.log(response.data)
            // Guessing Dispatcher and Constants are outside the class, but available
            Dispatcher.dispatch({
              actionType: Constants.CHANGE_ALL_PATIENTS,
              payload: response.data
            });
          })
          .catch(error => {console.log(error)});
      }
    
      // What you seem to be looking for
      createAndReload() {
        return this.createNewPatient()
          .then(() => this.reloadResults())
          .then(() => {
            console.log('done');
          });
      }
    }
    

    【讨论】:

    • 为什么有人对这个完全可以接受的答案投了反对票?虽然它可能不会重写原始代码,但它确实提供了解决他试图解决的问题所需的一切。我错过了问题中的关键内容吗?
    猜你喜欢
    • 2020-10-10
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 2022-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    相关资源
    最近更新 更多