【问题标题】:Receiving Promise {<pending>} back from .then()从 .then() 接收 Promise {<pending>}
【发布时间】:2018-02-13 13:15:27
【问题描述】:

我在api.js 中有一个 API 调用:

 export const getGraphData = (domain, userId, testId) => {
   return axios({
     url: `${domain}/api/${c.embedConfig.apiVersion}/member/${userId}/utests/${testId}`,
     method: 'get',
   });
 };

我有一个 React 助手,可以获取数据并对其进行转换。

import { getGraphData } from './api';

const dataObj = (domain, userId, testId) => {

  const steps = getGraphData(domain, userId, testId)
  .then((result) => {
    return result.attributes;
  });

  console.log(steps);

  // const steps = test.get('steps');
  const expr = /select/;

  // build array of steps that we have results in
  const resultsSteps = [];

  steps.forEach((step) => {
    // check for types that contain 'select', and add them to array
    if (expr.test(step.get('type'))) {
      resultsSteps.push(step);
    }
  });

  const newResultsSteps = [];

  resultsSteps.forEach((item, i) => {
    const newMapStep = new Map();
    const itemDescription = item.get('description');
    const itemId = item.get('id');
    const itemOptions = item.get('options');
    const itemAnswers = item.get('userAnswers');
    const newOptArray = [];
    itemOptions.forEach((element) => {
      const optionsMap = new Map();
      let elemName = element.get('value');
      if (!element.get('value')) { elemName = element.get('caption'); }
      const elemPosition = element.get('position');
      const elemCount = element.get('count');

      optionsMap.name = elemName;
      optionsMap.position = elemPosition;
      optionsMap.value = elemCount;
      newOptArray.push(optionsMap);
    });
    newMapStep.chartType = 'horizontalBar';
    newMapStep.description = itemDescription;
    newMapStep.featured = 'false';
    newMapStep.detailUrl = '';
    newMapStep.featuredStepIndex = i + 1;
    newMapStep.id = itemId;
    newMapStep.isValid = 'false';
    newMapStep.type = 'results';
    const listForNewOptArray = List(newOptArray);
    newMapStep.data = listForNewOptArray;
    newMapStep.userAnswers = itemAnswers;
    newResultsSteps.push(newMapStep);
  });

  return newResultsSteps;
};

export default dataObj;

问题是steps,当在.then() 之外登录时返回Promise {&lt;pending&gt;}。如果我在.then() 中记录results.attributes,我会看到数据完全返回。

【问题讨论】:

  • 您的混合同步和异步代码 - 您无法读取位于 getGraphData 链下的 steps 并期望它神奇地解决了。

标签: javascript reactjs es6-promise


【解决方案1】:

您需要等到异步调用得到解决。您可以通过链接另一个 then 来做到这一点:

getGraphData(domain, userId, testId)
  .then((result) => {
    return result.attributes;
  })
  .then(steps => {
     // put the rest of your method here
  });

如果您的平台支持,您也可以查看async/await,这将允许代码更接近您的原始代码

const steps = await getGraphData(domain, userId, testId)
  .then((result) => {
    return result.attributes;
  });

// can use steps here

【讨论】:

  • 实际上我认为result.attributes 在这种情况下不是一个承诺,这只是预期的结果,你调用了一个.then()
  • @Dyo 不,这不是它的工作方式。您可以从then 返回另一个承诺或值,但无论哪种方式,它都会解析为另一个承诺。如果您返回一个值,它会被包裹在 Promise.resolve(youReturnValue) 中。
  • 对于第二个.then() 块,如果我对其中的steps 进行任何处理,我会得到Uncaught (in promise) TypeError: steps.forEach is not a function
  • @Jamiec 我认为您将 response.json().then()fetch 库混淆了,axios 可以在一个承诺中显示结果数据。
  • @TWLATL 如果你在第二个console.log(steps) then 你会得到什么?
【解决方案2】:

您有 2 个选项来转换您获取的数据:

第一个选项:创建一个异步函数,返回带有修改后数据的承诺:

const dataObj = (domain, userId, testId) => {
  return getGraphData(domain, userId, testId).then((result) => {
    const steps = result.attributes;
    const expr = /select/;
    // build array of steps that we have results in
    const resultsSteps = [];

    steps.forEach((step) => {
      // check for types that contain 'select', and add them to array
      if (expr.test(step.get('type'))) {
        resultsSteps.push(step);
      }
    });

    const newResultsSteps = [];

    resultsSteps.forEach((item, i) => {
      const newMapStep = new Map();
      const itemDescription = item.get('description');
      const itemId = item.get('id');
      const itemOptions = item.get('options');
      const itemAnswers = item.get('userAnswers');
      const newOptArray = [];
      itemOptions.forEach((element) => {
        const optionsMap = new Map();
        let elemName = element.get('value');
        if (!element.get('value')) {
          elemName = element.get('caption');
        }
        const elemPosition = element.get('position');
        const elemCount = element.get('count');

        optionsMap.name = elemName;
        optionsMap.position = elemPosition;
        optionsMap.value = elemCount;
        newOptArray.push(optionsMap);
      });
      newMapStep.chartType = 'horizontalBar';
      newMapStep.description = itemDescription;
      newMapStep.featured = 'false';
      newMapStep.detailUrl = '';
      newMapStep.featuredStepIndex = i + 1;
      newMapStep.id = itemId;
      newMapStep.isValid = 'false';
      newMapStep.type = 'results';
      const listForNewOptArray = List(newOptArray);
      newMapStep.data = listForNewOptArray;
      newMapStep.userAnswers = itemAnswers;
      newResultsSteps.push(newMapStep);
    });
    return newResultsSteps;
  });
};

使用 es7 async/await 语法应该是:

const dataObj = async (domain, userId, testId) => {
    const result = await getGraphData(domain, userId, testId);
    const steps = result.attributes;
    ... modify the data
}

然后记住这个函数返回一个promise,你需要等待它得到结果,例如在一个react组件中:

componentDidMount(){
   dataObj('mydomain', 'myuserId', 'mytestId').then((res) => {
       this.setState({ data: res });
   }
}

当 promise 被解析时组件会更新,然后你可以使用数据(你需要在 render 方法中处理未定义的数据状态)

第二个选项:创建同步函数来修改数据:

const dataObj = (steps) => {
    const expr = /select/;
    const resultsSteps = [];

    steps.forEach((step) => {
    ...
    }
    return newResultsSteps;
};

为了在我们的组件中获得与选项 1 相同的结果,我们将这样使用它:

componentDidMount(){
   getGraphData('mydomain', 'myuserId', 'mytestId').then((res) => {
       const modifiedData = dataObj(res);
       this.setState({ data: modifiedData });
   }
}

【讨论】:

    【解决方案3】:

    这就是承诺的工作方式。当您尝试使用数据时,数据尚未准备好,因此您应该将所有处理移至.then。您的变量是 Promise {&lt;pending&gt;} 的原因是您可以将其他内容链接到它。

    类似:

    steps.then((steps) => {
        ...
    });
    

    【讨论】:

      猜你喜欢
      • 2019-05-10
      • 1970-01-01
      • 2020-11-17
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多