【问题标题】:Is it a good 'idea' to prevent nested promise with async / await?使用异步/等待防止嵌套承诺是一个好主意吗?
【发布时间】:2023-03-12 10:36:01
【问题描述】:

我对嵌套的 Promise 有一些困难(如下)。 现在我在 catch 中使用async function 来触发authentication Errors。

但这真的是一个好方法吗?难道没有更好的方法吗?

函数必须发送一个 POST 请求。如果authentication Error 被抛出然后login(),否则抛出错误。 如果满足login():重试POST(然后返回结果),否则抛出错误;

function getSomeData() {
    return post('mySpecialMethod');
}

function login() {
    const params = { /* some params */ }
  
    return post('myLoginMethod', params).then(result => {
        /* some processing */
        return { success: true };
    });
}

const loginError = [1, 101];
function post(method, params, isRetry) {
    const options = /* hidden for brevity */;
    
    return request(options)
        // login and retry if authentication Error || throw the error
        .catch(async ex => {
            const err = ex.error.error || ex.error

            if (loginError.includes(err.code) && !isRetry) { // prevent infinite loop if it's impossible to login -> don't retry if already retried
                await login();
                return post(method, params, true)
            } else {
                throw err;
            }
        })
        // return result if no error
        .then(data => {
            // data from 'return request(options)' or 'return post(method, params, true)'
            return data.result
        });
}

使用

getSomeData.then(data => { /* do something with data */});

【问题讨论】:

  • 这不起作用:您正在执行“如果没有错误则返回结果”,即使出现错误并且您从重试中得到了一些回报,您然后再次访问.result

标签: javascript node.js promise nested


【解决方案1】:

一般来说这不是什么大问题。您可以像这样链接/封装异步调用。

在逻辑方面,这取决于您的需求。我认为在调用任何需要身份验证的 API 方法之前,应该检查用户的登录状态。

【讨论】:

    【解决方案2】:

    ...但它真的是一个好方法吗?没有更好的方法吗?

    不,这不是一个好主意,因为它会伤害code readability

    您正在混合 2 个可互换概念,Promise.then/catchasync/await。将它们混合在一起会以mental context switching 的形式产生可读性开销。

    任何阅读您的代码的人,包括您,都需要在异步流程 (.then/.catch) 与同步流程 (async/await) 的思维方式之间不断切换。

    使用一个或另一个,最好是后者,因为它更具可读性,主要是因为它是同步流。

    虽然我不同意您处理登录的方式,但我将重写您的代码以使用 async/awaittry...catch 进行异常处理:

    function getSomeData() {
        return post('mySpecialMethod')
    }
    
    async function login() {
        const params = { } // some params
    
        await post('myLoginMethod', params)
    
        return { success: true }
    }
    
    const loginError = [1, 101]
    
    async function post(method, params, isRetry) {
        const options = {} // some options
    
        try {
            const data = await request(options)
    
            return data.result
        } catch (ex) {
            const err = ex.error.error || ex.error
    
            if (err) throw err
    
            if (loginError.includes(err.code) && !isRetry) {
                await login()
    
                return post(method, params, true)
            }
    
            throw err
        }
    }
    

    我显然不能/没有测试上述内容。

    【讨论】:

      【解决方案3】:

      我建议对于复杂的逻辑,至少您使用 async/await 语法。

      当然 .then() 等是完全有效的,但是你会发现回调的嵌套很难处理。

      我的规则(就像编程中的很多事情一样)是使用上下文来做出决定。 .then() 在处理有限数量的 promise 时效果很好。当您处理更复杂的逻辑时,这开始变得尴尬。

      将 async / await 用于更多涉及的逻辑,可以让您的代码结构更像同步代码,因此更直观和可读。

      下面显示了两种方法的示例(具有相同的基本目标)。我认为 async / await 版本更具可读性。

      Async / await 也使循环异步任务变得容易,您可以使用 for 循环或 for ... of 循环与 await 并且任务将按顺序执行。

      function asyncOperation(result) {
          return new Promise(resolve => setTimeout(resolve, 1000, result));
      }
      
      async function testAsyncOperationsAwait() {
          const result1 = await asyncOperation("Some result 1");
          console.log("testAsyncOperationsAwait: Result1:", result1);
          const result2 = await asyncOperation("Some result 2");
          console.log("testAsyncOperationsAwait: Result2:", result2);
          const result3 = await asyncOperation("Some result 3");
          console.log("testAsyncOperationsAwait: Result3:", result3);
      }
      
      
      function testAsyncOperationsThen() {
          return asyncOperation("testAsyncOperationsThen: Some result 1").then(result1 => {
              console.log("testAsyncOperationsThen: Result1:", result1);
              return asyncOperation("testAsyncOperationsThen: Some result 2").then(result2 => {
                  console.log("testAsyncOperationsThen: Result2:", result2);
                  return asyncOperation("testAsyncOperationsThen: Some result 3").then(result3 => {
                      console.log("testAsyncOperationsThen: Result3:", result3);
                  })
              })
          })
      }
      
          
      async function test() {
          await testAsyncOperationsThen();
          await testAsyncOperationsAwait();	
      }
      
      test();

      【讨论】:

        【解决方案4】:

        还值得探索提供重试功能的库。

        类似https://www.npmjs.com/package/async-retry

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-20
          • 2018-02-03
          • 2018-03-05
          相关资源
          最近更新 更多