如何从 redux 操作中的递归承诺中获取结果

how to get the result from recursive promises in a redux action

我已经在网上搜索过,但找不到解决方案。我的最终目标是从 dynamodb table 中提取所有数据。问题是当 table 大于 1MB 时,在响应中我将获得一个数据块和一个 LastEvaluatedKey 参数(它提供了我可以在下一次调用中使用的索引来获取下一个块)。如果需要,scan 操作被记录在案 here

我在我的应用程序中使用了 reactjs、redux 和 redux-thunk。

我在单一或链式格式中适度使用了 promises,但这个更具挑战性,我目前可以解决。令我困惑的是,如果没有收到先前的响应,就无法拨打新的电话,所以我认为这些电话不能同时进行。另一方面,由于 scan 操作是一个承诺(据我所知),如果我尝试 return 来自我自己的方法的承诺,该操作不会收到结果。

我很困惑,我真的很想了解如何让它发挥作用。

动作:

function getDynamodbTableRecords(tableName) {
    return dispatch => {
        dispatch(request());

        var recordsSet = [];
        var data = myAwsService.getTableRecords(tableName, null) || {Items:[]};
        if (data.Items.length > 0){
            data.Items.map(record => {
                recordsSet.push(record);
            });

            dispatch(success(recordsSet));
        } else {
            dispatch(failure("No Records Found!"));
        }
    };

    function request() { return { type: DATA_LOADING, selectedTable: tableName } }
    function success(tableRecords) { return { type: DATA_LOAD_SUCCESS, tableRecords } }
    function failure(error) { return { type: DATA_LOAD_FAILED, errors: error } }
}

myAwsService:

function getTableRecords(tableName, lastEvaluatedKey = null) {
    getRecordsBatch(tableName, lastEvaluatedKey)
    .then(
        data => {
            if (data.LastEvaluatedKey) {
                return getTableRecords(tableName, data.LastEvaluatedKey)
                .then(
                    nextData => {
                        data.Items = data.Items.concat(nextData.Items);
                    }
                )
            }

            return data;
        }
    )
}

function getRecordsBatch(tableName, lastEvaluatedKey = null) {
    var awsDynamodb = new DynamoDB();

    let params = { TableName: tableName };
    if (lastEvaluatedKey) {
        params['ExclusiveStartKey'] = lastEvaluatedKey;
    }

    return new Promise((resolve, reject) => {
        awsDynamodb.scan(params, function(err, data) {
            if (err) {
                reject(err);
            }

            return resolve(data);
        });
    });
}

不确定你的递归承诺是否有效,但我会这样做:

function getTableRecords(
  tableName,
  lastEvaluatedKey = null,
  result = { Items: [] }
) {
  return getRecordsBatch(tableName, lastEvaluatedKey).then(
    data => {
      if (data.LastEvaluatedKey) {
        return getTableRecords(
          tableName,
          data.LastEvaluatedKey,
          {
            ...data,
            Items: result.Items.concat(data.Items),
          }
        );
      }

      return {
        ...data,
        Items: result.Items.concat(data.Items),
      };
    }
  );
}

该操作还应分派 data.Items 而不是 getTabelRecords returns 的承诺,如果出现问题,您可能希望分派失败操作:

function getDynamodbTableRecords(tableName) {
  return async dispatch => {
    dispatch(request());

    //you probably want the data, not a promise of data
    try {
      var data = await myAwsService.getTableRecords(
        tableName,
        null
      );
      if (data.Items.length > 0) {
        //no reason to have the temporary recordSet variable
        dispatch(success(data.Items.map(record => record)));
      } else {
        dispatch(failure('No Records Found!'));
      }
    } catch (e) {
      dispatch(failure(e.message));
    }
  };

  function request() {
    return { type: DATA_LOADING, selectedTable: tableName };
  }
  function success(tableRecords) {
    return { type: DATA_LOAD_SUCCESS, tableRecords };
  }
  function failure(error) {
    return { type: DATA_LOAD_FAILED, errors: error };
  }
}