使用Promise.all反应SetState竞争条件

时间:2019-07-10 13:26:45

标签: javascript reactjs refluxjs

componentDidMount() {
    Promise.all([OfferCreationActions.resetOffer()]).then( () => {
        OfferCreationActions.updateOfferCreation('viewOnly', true);
        OfferCreationActions.updateOfferCreation('loadingOffer', true);
        Promise.all([
            OfferCreationActions.loadBarcodes(),
            OfferCreationActions.loadBrandBarcodes(),
            OfferCreationActions.loadBrands(),
            OfferCreationActions.loadPayers(),
            OfferCreationActions.loadSegments(),
            OfferCreationActions.loadTactics(),
            OfferCreationActions.loadStates(),
        ]).then(() => {
            // let state settle before loading
            setTimeout(() => {
                OfferCreationActions.loadOffer(this.props.match.params.offerId);
            }, 1500);
        });
    });
}

我正在开发一个React应用,该应用需要将一些数据预加载到状态中,然后加载一个更大的对象,该对象引用预加载的数据以映射某些字段。我遇到了一种竞争情况,在这种情况下,当我尝试执行映射时,仍会处理来自promise链的某些数据。我昨天添加了超时时间,但这对我来说并不是最好的解决方案。我对React还是很陌生,我们使用Reflux作为商店(如果有所作为)。有没有更好的方法来确保在发出呼叫之前,来自承诺的所有数据当前都已反映在状态中?我应该挂接到componentShouldUpdate并单独检查所有字段吗?

1 个答案:

答案 0 :(得分:0)

实施此方法存在一个根本缺陷!您正在打破单向数据流的原理。这里有一些修复建议。

  
      
  1. 在单独的总体功能中进行副作用处理。
  2.   

处理promise竞争条件是一个副作用(在React的UniFlow之外的某些东西)。因此,这不是与“反应”关联的问题。因此,作为onComponentDidMount的第一步,将此竞态条件逻辑委托给一个单独的动作。可能在“ resetOfferOverall()”内部执行此操作,我想这实际上就是正在发生的事情。

  
      
  1. 管理动作中的promise,并将有效载荷分配给商店
  2.   

在您的代码中,可以保证在答应解决后将执行“ then”。但是,对这两个调用“ updateOfferCreation”的调用不属于此合同,因为它不在promise.all之内。也许他们还需要进入大规模的promise.all部分?可能需要在运行大量部分之前完成它们。只需重新检查一下即可!

resetOfferOverall() {
    Promise.all([OfferCreationActions.resetOffer()]).then( () => {
    .then( () => {

        // These are not guaranteed to be completed before the next "then" section!
        OfferCreationActions.updateOfferCreation('viewOnly', true);
        OfferCreationActions.updateOfferCreation('loadingOffer', true);
        //*****************************************

        Promise.all([
            OfferCreationActions.loadBarcodes(),
            OfferCreationActions.loadBrandBarcodes(),
            OfferCreationActions.loadBrands(),
            OfferCreationActions.loadPayers(),
            OfferCreationActions.loadSegments(),
            OfferCreationActions.loadTactics(),
            OfferCreationActions.loadStates(),
        ]).then(() => {               
            OfferCreationActions.loadOffer(offerId);
        });
    });
}
  

如果您希望在完成本节之前完成本节   所有人,请按如下所示更改您的代码。

async resetOfferOverall() {
    Promise.all([OfferCreationActions.resetOffer()]).then( () => {
    .then( () => {

        await OfferCreationActions.updateOfferCreation('viewOnly', true);
        await  OfferCreationActions.updateOfferCreation('loadingOffer', true);
        //await will stop code execution until the above async code is completed

        Promise.all([
            OfferCreationActions.loadBarcodes(),
            OfferCreationActions.loadBrandBarcodes(),
            OfferCreationActions.loadBrands(),
            OfferCreationActions.loadPayers(),
            OfferCreationActions.loadSegments(),
            OfferCreationActions.loadTactics(),
            OfferCreationActions.loadStates(),
        ]).then(() => {   
            //Now JS Guarantees that this call will not be called until everything above has been resolved!            
            OfferCreationActions.loadOffer(offerId);
        });
    });
}
  
      
  1. 确保您正在等待的操作正在返回承诺
  2.   

无论等待什么方式,如果您没有真正返回调用本身内的相关诺言,您的代码将无法正常工作。让我们考虑加载条形码操作,并假设您使用axios来获取数据。

loadBarcodes(){
    // This "return" right here is vital to get your promises to behave properly
    return axios.get('https://localhost:8080/api/barcodes/').then((response) =>{
        //DISPATCH_TO_STORE
    });

    //If you did not return this promise this call will resolve immediately

}
  
      
  1. 在组件上,注意relevent存储区。显示一个加载器,直到将有效负载加载到商店。
  2.   

如您所见,依靠商店更新来显示数据,我们不会中断单向数据流。