简体   繁体   English

使用异步/等待防止嵌套承诺是一个好“主意”吗?

[英]Is it a good 'idea' to prevent nested promise with async / await?

I have some difficulties with a nested promise (below).我在嵌套承诺(如下)方面遇到了一些困难。 For now I'm using an async function in the catch to trigger authentication Error s.现在我在 catch 中使用async function来触发authentication Error s。

But is it really a good way and isn't there a better way ?但这真的是一个好方法吗,难道没有更好的方法吗?

The function have to send a POST request.该函数必须发送 POST 请求。 If an authentication Error is thrown then login() , else throw the error.如果抛出authentication Error ,则login() ,否则抛出错误。 If login() is fulfilled : retry the POST (and then return the results), else throw the error;如果满足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
        });
}

Use

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

... But is it really a good way and isn't there a better way ? ...但这真的是一个好方法吗?难道没有更好的方法吗?

No it's not a good idea because it hurts code readability .不,这不是一个好主意,因为它损害了代码的可读性

You're mixing 2 interchangeable concepts, Promise.then/catch and async/await .您正在混合 2 个可互换的概念, Promise.then/catchasync/await Mixing them together creates readability overhead in the form of mental context switching .将它们混合在一起会以心理上下文切换的形式产生可读性开销。

Anyone reading your code, including you, would need to continuously switch between thinking in terms of asynchronous flows( .then/.catch ) vs synchronous flows ( async/await ).任何阅读您代码的人,包括您,都需要在异步流( .then/.catch )与同步流( async/await )之间不断切换。

Use one or the other, preferably the latter since it's more readable, mostly because of it's synchronous flow.使用一个或另一个,最好是后者,因为它更具可读性,主要是因为它是同步流程。

Although I don't agree with how you're handling logins, here's how I would rewrite your code to use async/await and try...catch for exception handling:虽然我不同意您处理登录的方式,但我将重写您的代码以使用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
    }
}

I obviously cannot/didn't test the above.我显然不能/没有测试上述内容。

I'd suggest that for complex logic at least you use the async/await syntax.我建议对于复杂的逻辑,至少你使用 async/await 语法。

Of course .then() etc is perfectly valid, however you will find the nesting of callbacks awkward to deal with.当然 .then() 等是完全有效的,但是你会发现回调的嵌套很难处理。

My rule (like a lot of things in programming) is use context to make your decision.我的规则(就像编程中的很多事情一样)是使用上下文来做出决定。 .then() works nicely when you're dealing with a limited number of promises.当您处理数量有限的承诺时,.then() 工作得很好。 This starts to get awkward when you're dealing with more complex logic.当您处理更复杂的逻辑时,这开始变得尴尬。

Using async / await for more involved logic allows you to structure your code more like synchronous code, so it's more intuitive and readable.使用 async/await 处理更多复杂的逻辑可以让你的代码结构更像同步代码,所以它更直观和可读。

An example of two approaches is shown below (with the same essential goal).下面显示了两种方法的示例(具有相同的基本目标)。 The async / await version is the more readable I believe.我相信 async / await 版本更具可读性。

Async / await also makes looping over asynchronous tasks easy, you can use a for loop or a for ... of loop with await and the tasks will be performed in sequence. 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();

Also worth exploring the libraries which provides retry functionalities.同样值得探索提供重试功能的库。

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

Generally this is not a big problem.一般来说,这不是什么大问题。 You can chain/encapsulate async calls like this.您可以像这样链接/封装异步调用。

When it comes to logic it depends on your needs.说到逻辑,这取决于您的需求。 I think the login state of a user should be checked before calling any API methods that require authentication.我认为在调用任何需要身份验证的 API 方法之前,应该检查用户的登录状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM