1

我正在尝试从 API 获取数据,但结果一直未定义。我正在使用 promise.all 链接 API 调用,然后链接 promise 以对数据执行其他操作。我似乎无法将我的结果传递给州。

这是有问题的代码:

if (gameDifficulty === "mixed") {
  const result = await Promise.all([
    fetchClient.getData(
      getEndpoint(
        `amount=${countValues[0]}&difficulty=easy&type=${questionType}`
      )
    ),
    fetchClient.getData(
      getEndpoint(
        `amount=${countValues[1]}&difficulty=medium&type=${questionType}`
      )
    ),
    fetchClient.getData(
      getEndpoint(
        `amount=${countValues[2]}&difficulty=hard&type=${questionType}`
      )
    ),
  ])
    .then(function (responses) {
      console.log(responses);
      console.log(result); //returns undefined
      return Promise.all(
        responses.map(function (response, idx) {
          return fetchClient.processData(response, "results");
        })
      );
    })
    .then(function (data) {
      console.log(data);

      console.log(result); // returns undefined
      return [...data[0], ...data[1], ...data[2]];
    });
}
4

4 回答 4

0

其他答案显示了如何更正代码,同时避免混淆承诺链和await运算符的使用。这个答案是关于为什么result会出现未定义的值:

 const result = await <promise chain>

result在执行操作数之前创建一个绑定await。像所有简单的变量定义一样,它以 的值开始undefined,并且因为它现在存在,result在以后的代码中访问不会产生错误。

Promise 链的对象值是链中调用的最后一个 Promise 方法(即 或 )返回thencatchPromise finally。这是await操作数在返回其(成功)值作为await表达式值之前等待解决的承诺。

因此,直到最后一个处理程序返回之后才await返回要分配的值,这意味着在匿名函数之后resultthen

.then(function (data) {
  console.log(data);

  console.log(result); // returns undefined
  return [...data[0], ...data[1], ...data[2]];
});

已完成执行并返回。在那之前,所有的console.log(result)呼叫都会记录下来undefined,因为没有分配到result


TLDR;

附加到 Promise 的处理程序是异步执行的,在事件循环的新调用中,在它们附加到的 Promise 被履行或拒绝之后。

await是一个一元运算符,能够保存执行状态并返回事件循环,直到它的承诺操作数被解决。

贴出代码的操作顺序是

  1. 定义result,将其初始化undefined并设置await操作符以获取then第 5 步返回的 promise 的结果。

  2. 发出三个端点数据请求。

  3. 用于Promise.all从步骤 2 中获取一系列响应。

  4. (then) 用于Promise.all从步骤 3 的结果中异步获取数组中每个响应的过程数据数组。

  5. (然后)展平步骤 4 中的数据数组并返回展平后的数组

  6. (then)await操作符获取带有第 5 步结果的回调,并将其作为await表达式的值返回

  7. 从第 6 步返回的值用于初始化const result声明。从语法上讲,这发生在const result语句结束之前,但实际上已经分散了多个网络请求和事件循环调用所需的时间。

于 2021-01-22T05:25:11.053 回答
0

在您的浏览器中转到您的网络选项卡发送一个 api 请求,看看它是否正在发送任何飞行前请求?

飞行前请求将具有 OPTIONS 方法,因此您将识别它

于 2021-01-22T03:55:19.583 回答
0

async/await用语法让它变得简单。

避免async/awaitthen/catch风格混搭。

const getDataResponses = await Promise.all([
  fetchClient.getData(
    getEndpoint(
      `amount=${countValues[0]}&difficulty=easy&type=${questionType}`
    )
  ),
  fetchClient.getData(
    getEndpoint(
      `amount=${countValues[1]}&difficulty=medium&type=${questionType}`
    )
  ),
  fetchClient.getData(
    getEndpoint(
      `amount=${countValues[2]}&difficulty=hard&type=${questionType}`
    )
  ),
]);

const data = await Promise.all(
  getDataResponse.map((response) => {
    return fetchClient.processData(response, "results");
  })
);

console.log('getDataResponses', getDataResponses);
console.log('processDataResponse', data);
return [...data[0], ...data[1], ...data[2]];
于 2021-01-22T04:11:34.507 回答
0

由于result直接从awaiton获取值,Promise因此您可以使用它而不是.then().

const responses = await Promise.all([
    fetchClient.getData(
        getEndpoint(
            `amount=${countValues[0]}&difficulty=easy&type=${questionType}`
        )
    ),
    fetchClient.getData(
        getEndpoint(
            `amount=${countValues[1]}&difficulty=medium&type=${questionType}`
        )
    ),
    fetchClient.getData(
        getEndpoint(
            `amount=${countValues[2]}&difficulty=hard&type=${questionType}`
        )
    ),
])

console.log('responses', responses);

const data = await Promise.all(
    responses.map(function (response, idx) {
        return fetchClient.processData(response, "results");
    })
);

console.log('data', data);
console.log([...data[0], ...data[1], ...data[2]]);
于 2021-01-22T04:29:44.380 回答