【问题标题】:difference using async vs return new Promise使用异步与返回新 Promise 的区别
【发布时间】:2023-01-08 01:37:41
【问题描述】:

我试图从 NextJS API 页面调用异步实用程序函数,但未定义。 当我转到 localhost:300/api/hello 时,控制台打印以下内容

result =  undefined

文件一:api/hello.js

export default function handler(req, res) {
  getCountries().then(result=>{
    console.log('result = ', result);
    res.status(200).json({ status: 'ok', data: result.data });
  }).catch(err=>{
    console.log('error = ', err);
    res.status(500).json({ status: 'error', error: err });    
  })
}

文件 2:utils/getCountries.js

const getCountries = async () => {
    var response = [];
    var params = { action: "get_countries", ...authKey }
    axios.get(APIFOOTBALL_URL, { params: params })
        .then((result) => {
          response = [...result.data];
          return response;
        }).catch((err) => {
            throw err;
        });
}

export default getCountries;

将 getCountries 函数更改为以下有效,但我不明白为什么。 async 不也返回一个 promise 吗? 如果一定要写在async/await方法中,应该怎么办?

文件 2:utils/getCountries.js

const getCountries = () => {
    return new Promise((resolve, reject) =>{
        var response = [];
        var params = { action: "get_countries", ...authKey }
    
        axios.get(APIFOOTBALL_URL, { params: params })
            .then((result) => {
              response = [...result.data];
              resolve(response);
            }).catch((err) => {
                reject;
            });
    })
}

【问题讨论】:

  • 你在第一个版本中没有返回任何东西。 undefined 中函数的默认返回值。你需要像return axios.get(...这样的东西

标签: node.js next.js async-await es6-promise


【解决方案1】:

async 函数中,您必须 await 您的承诺,否则您必须返回它。没有其中之一,实际上没有任何东西等待那个承诺或传达它的任何结果。因为使用async 的目的是为了能够使用await,所以它看起来像这样:

const getCountries = async () => {
    const params = { action: "get_countries", ...authKey }
    const result = await axios.get(APIFOOTBALL_URL, { params: params });
    return result.data;
}

或者,您可以只返回 promise 而不需要 async

const getCountries = () => {
    const params = { action: "get_countries", ...authKey }
    return axios.get(APIFOOTBALL_URL, { params: params }).then(result =>{
        return result.data;
    });
}

关于您的代码的其他一些注意事项:

  1. 没有理由再使用var。在所有现代 Javascript 中使用 letconst 代替。
  2. 没有理由用response = [...result.data];复制数据。你可以做return result.data
  3. 您的最后一个代码块被认为是承诺反模式。您永远不想用手动创建的承诺包装现有的承诺(axios.get() 调用的返回)。这只是没有必要,并且经常会产生错误处理问题,而您确实遇到了错误处理,因为您没有正确调用reject(err)
  4. 没有理由让.catch()只做throw err,除非你在.catch()中还有一些其他代码(比如记录错误)。

【讨论】:

    【解决方案2】:

    getCountries 的第一个示例中,您返回一个无任何承诺(未定义),而在第二个示例中,您返回一个响应承诺。

    在您的第一个示例中发生的事情是,axios.get 运行,但是没有什么能真正阻止函数返回。在axios.get 上调用.then 的全部意义在于,.then 回调中的任何内容都会在承诺得到解决后执行。否则,您可能只是在 axios.get 调用之后像往常一样在 .then 中编写您正在编写的代码,如果您使用 await,您可以这样做。使用 await 将停止代码执行,直到承诺被解决或拒绝(这就是为什么你应该只在 try-catch 块中使用 await 的原因。

    如果你的第一个例子重构如下:

    const getCountries = async () => {
        var response = [];
        var params = { action: "get_countries", ...authKey }
        try {
            const result = await axios.get(APIFOOTBALL_URL, { params: params });
            const response = [...result.data];
            return response;
        } catch (err) {
            console.error("An error occurred while trying to fetch countries: ", err);
            throw err;
        }
    }
    

    您最终会在 axios.get 调用之后阻止代码的执行,直到该承诺被解决或拒绝。

    简而言之,您的第一个示例不起作用的原因是因为您的函数在 axios.get 调用之后返回 undefined (隐含地,因为您的第一个示例中没有 return 语句)。没有什么能阻止它返回,所以你的第一个例子返回的承诺总是用 undefined 值来解决。

    你的第二个例子之所以有效,是因为当你手动返回一个承诺时,它总是挂起,直到你用resolve(response);reject手动解决它。

    如果这没有帮助,请这样考虑 -> 在调用代码中,当您执行 getCountries.then 时,.then 部分仅在解决承诺时执行。它解析的值被传递给回调(您将其用作result)。在您的第一个示例中,getCountries 立即解析为 undefined 的值,因此您的回调获取 undefined 值,而在第二个示例中,getCountries 返回的承诺一直待定,直到调用 resolve您的代码,这只会在您的 API 请求承诺解决后发生(因为您是在 axios.get.then 回调中调用它)。

    此外,在您的第一个示例中,当您在 axios.get.then 部分执行 return response; 时,您将返回 .then 的回调函数。这不会返回 getCountries 函数。也许这使您认为这应该有效,但实际上无效。

    如果你这样做,你的第一个例子也可以工作:

    const getCountries = async () => {
        var response = [];
        var params = { action: "get_countries", ...authKey }
        return axios.get(APIFOOTBALL_URL, { params: params })
            .then((result) => {
              response = [...result.data];
              return response;
            }).catch((err) => {
                throw err;
            });
    }
    

    因为现在,getCountries 正在返回响应的承诺,而不仅仅是返回 undefined 的承诺。

    最后,正如@jfriend00 提到的,.catch() 没有理由只会再次抛出错误。 catch 的目的是处理错误(记录或处理错误)。您现在使用.catch() 的方式与不使用它一样好。

    【讨论】:

      猜你喜欢
      • 2018-04-13
      • 2020-06-08
      • 1970-01-01
      • 2018-11-17
      • 2018-03-08
      • 1970-01-01
      • 2020-07-09
      • 2017-10-16
      • 1970-01-01
      相关资源
      最近更新 更多