如何取消这些承诺的嵌套? [英] How to unnest these Promises?

查看:63
本文介绍了如何取消这些承诺的嵌套?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个向服务器发出请求的功能。如果请求失败,我要:
1.记录错误
2.运行终端命令
2.1记录命令失败或成功

I have a function that makes a request to a server. If the request fails, I want to: 1. log the error 2. run a terminal command 2.1 log if the command failed or succeeded

要实现这一点,我需要以下代码:

To achieve this I have the following code:

const createRequest = ( { request, logger, terminal } ) => ( { endpoint, timeout } ) =>
    request.get( endpoint, { timeout } )
        .then( response =>
            logger.info( { event: "Heartbeat request succeeded.", status: response.status } )
        )
        .catch( err =>
            logger.error( { event: "Heartbeat request failed.", err } )
                .then( ( ) => terminal.runAsync( "pm2 restart myAPI" ) )
                .then( ( ) => logger.info( { event: "Restarted API." } ) )
                .catch( err => logger.error( { event: "Failed to restart API.",  err } ) )
        );

现在,有几件事需要注意:
-日志记录是异步的(发送信息到远程服务器)
-运行终端命令是异步
-使请求(显然)是异步

Now, there are a few things to notice: - logging is async ( sends info to a remote server ) - running the terminal command is async - making the request is ( obviously ) async

我的问题是我的渔获里面有一个Promise,这意味着我有嵌套。
现在,我强烈反对应许的嵌套,所以我真的想摆脱它,但我只是不知道如何。

The problem I have is that my catch has a Promise inside, which means I have nesting. Now, I am strongly against nesting of promises, so I really want to get rid of that, but I just don't see how.


  1. 是否有可能摆脱 catch 内的嵌套承诺?

  2. 是否这样?

  1. Is it possible to get rid of nesting promises inside a catch ?
  2. If so how?


推荐答案


问题?

我的问题是我的渔获物内部有一个Promise,这意味着我有嵌套。现在,我强烈反对应许的嵌套,所以我真的想摆脱它,但是我只是不知道如何。

The problem I have is that my catch has a Promise inside, which means I have nesting. Now, I am strongly against nesting of promises, so I really want to get rid of that, but I just don't see how.

– Flame_Phoenix

– Flame_Phoenix

问题是您认为自己有问题–或者您是在StackOverflow而不是CodeReview 链接的文章显示了您对嵌套的Promise采取幼稚的看法

The problem is that you think you have a problem – or maybe that you posted this question on StackOverflow instead of CodeReview. The article you linked shows where you adopt a naive view about nested promises


您会得到一大堆彼此嵌套的承诺:

You get a whole bundle of promises nested in eachother:

loadSomething().then(function(something) {
    loadAnotherthing().then(function(another) {
                    DoSomethingOnThem(something, another);
    });
});

这样做的原因是因为您需要对两个诺言的结果都做点事情,所以您不能链接它们,因为then()仅传递了前一个返回的结果。

The reason you’ve done this is because you need to do something with the results of both promises, so you can’t chain them since the then() is only passed the result of the previous return.

您这样做的真正原因是因为您没有不知道 Promise.all()方法。

The real reason you’ve done this is because you don’t know about the Promise.all() method.

–代码猴子, http://taoofcode.net

否, Promise.all 只能有时替换嵌套的承诺。一个简单的反例–在这里,一个承诺的价值取决于另一个,因此两个必须进行排序

No, Promise.all can only sometimes replace nested promises. A simple counter-example – here, one promise's value depends on the the other and so the two must be sequenced

getAuthorByUsername (username) .then (a => getArticlesByAuthorId (a.id))



Nesting promises is not always necessary, but calling it an "anti-pattern" and encouraging people to avoid it before they know the difference is harmful, imo.

语句不起作用

其他链接文章显示了您可能再次被误导的地方

The other linked article shows where you may have been misguided again


别误会我的意思,异步/等待并不是世界上所有邪恶的源头。经过几个月的使用,我实际上学会了喜欢它。因此,如果您舒适地编写命令式代码,那么学习如何使用async / await来管理异步操作可能是个不错的选择。

Don’t get me wrong, async/await is not the source of all evil in the world. I actually learned to like it after a few months of using it. So, if you feel confortable writing imperative code, learning how to use async/await to manage your asynchronous operations might be a good move.

但是如果您喜欢promises并且您想要学习越来越多的函数式编程原理并将其应用到您的代码中,您可能希望完全跳过异步/等待代码,停止思考必要的命令,而转向这种新的旧模式。

But if you like promises and you like to learn and apply more and more functional programming principles to your code, you might want to just skip async/await code entirely, stop thinking imperative and move to this new-old paradigm.

– Gabriel Montes

– Gabriel Montes

这只是没有任何意义。如果您查看JavaScript中的所有命令式关键字,就会发现它们都不会对值求值。为了说明我的意思,请考虑

Only this doesn't make any sense. If you look at all of the imperative keywords in JavaScript, you'll notice none of them evaluate to a value. To illustrate what I mean, consider

let total = if (taxIncluded) { total } else { total + (total * tax) }
// SyntaxError: expected expression, got keyword 'if'

在另一个表达式中间使用 if

Or if we try to use if in the middle of another expression

makeUser (if (person.name.length === 0) { "anonymous" } else { person.name })
// SyntaxError: expected expression, got keyword 'if'

这是因为 if 声明,并且永远不会求值–相反,它只能依靠副作用。

That's because if is a statement and it never evaluates to a value – instead, it can only rely on side effects.

if (person.name.length === 0)
  makeUser ("anonymous") // <-- side effect
else
  makeUser (person.name) // <-- side effect

以下永远不会求值。相反,它依靠副作用来计算 sum

Below for never evaluates to a value. Instead it relies on side effects to compute sum

let sum = 0
let numbers = [ 1, 2, 3 ]
for (let n of numbers)
  sum = sum + n        // <-- side effect
console.log (sum)      // 6

do 开关,甚至返回和所有其他命令式关键字-它们都是语句,因此依赖于副作用来计算值。

The same is true for do, while, switch, even return and all of the other imperative keywords – they're all statements and therefore rely upon side effects to compute values.

然后求值的值? 表达式评估为值

What evaluates to a value then? Expressions evaluate to a value

1                          // => 1
5 + 5                      // => 10
person.name                // => "bobby"
person.name + person.name  // => "bobbybobby"
toUpper (person.name)      // => "BOBBY"
people .map (p => p.name)  // => [ "bobby", "alice" ]






async await 不是语句


async and await are not statements

您可以将异步函数分配给变量

You can assign an asynchronous function to a variable

const f = async x => ...

或者您可以将异步函数作为参数传递

Or you can pass an asyncrhonous function as an argument

someFunc (async x => ... )

即使 async 函数不返回任何内容, async 仍然保证我们将收到Promise值

Even if an async function returns nothing, async still guarantees we will receive a Promise value

const f = async () => {}
f () .then (() => console.log ("done"))
// "done"

您可以等待一个值并将其分配给变量

You can await a value and assign it to a variable

const items = await getItems () // [ ... ]

或者您可以等待另一个表达式中的值

Or you can await a value in another expression

items .concat (await getMoreItems ()) // [ ... ]

这是因为 async / await 形式的表达式可以与功能样式一起使用。如果您尝试学习功能样式并避免 async await ,那仅仅是因为您被误导了。如果 async await 仅是命令式的,这样的事情将永远不可能

It's because async/await form expressions that they can be used with functional style. If you are trying to learn functional style and avoid async and await, it is only because you've been misguided. If async and await were imperative style only, things like this would never be possible

const asyncUnfold = async (f, initState) =>
  f ( async (value, nextState) => [ value, ...await asyncUnfold (f, nextState) ]
    , async () => []
    , initState
    )






真实示例

这是一个实际的示例,其中我们有一个记录数据库,我们希望执行递归查找或其他操作。

Here's a practical example where we have a database of records and we wish to perform a recursive look-up, or something...

const data =
  { 0 : [ 1, 2, 3 ]
  , 1 : [ 11, 12, 13 ]
  , 2 : [ 21, 22, 23 ]
  , 3 : [ 31, 32, 33 ]
  , 11 : [ 111, 112, 113 ]
  , 33 : [ 333 ]
  , 333 : [ 3333 ]
  }

异步函数 Db.getChildren 站在您和您的数据之间。您如何查询节点及其后代的所有

An asynchronous function Db.getChildren stands between you and your data. How do you query a node and all of its descendants?

const Empty =
  Symbol ()

const traverse = (id) =>
  asyncUnfold
    ( async (next, done, [ id = Empty, ...rest ]) =>
        id === Empty
          ? done ()
          : next (id, [ ...await Db.getChildren (id), ...rest ])
    , [ id ]
    )

traverse (0)
// => Promise [ 0, 1, 11, 111, 112, 113, 12, 13, 2, 21, 22, 23, 3, 31, 32, 33, 333, 3333 ]

从 JavaScript开发人员天堂发送的一个纯程序,用Montes的话来说就是。它是使用函数表达式编写的,错误相应地冒出,我们什至不必触摸。然后

A pure program sent from the "heaven of JavaScript developers", to put it in the words of Montes. It's written using a functional expression, errors bubble up accordingly, and we didn't even have to touch .then.

我们可以使用命令式风格编写相同的程序。或者我们也可以使用来编写功能样式。然后。我们可以用各种方式来编写它,我想这就是关键–感谢 async await 的能力形式 expressions ,我们可以以多种样式使用它们,包括功能样式。

We could write the same program using imperative style. Or we could write it functional style using .then too. We can write it all sorts of ways and I guess that's the point – Thanks to async and await's ability to form expressions, we can use them in a variety of styles, including functional style.

在下面的浏览器中运行整个程序

Run the entire program in your browser below

const asyncUnfold = async (f, init) =>
  f ( async (x, acc) => [ x, ...await asyncUnfold (f, acc) ]
    , async () => []
    , init
    )

const Db =
  { getChildren : (id) =>
      new Promise (r => setTimeout (r, 100, data [id] || []))
  }

const Empty =
  Symbol ()

const traverse = (id) =>
  asyncUnfold
    ( async (next, done, [ id = Empty, ...rest ]) =>
        id === Empty
          ? done ()
          : next (id, [ ...await Db.getChildren (id), ...rest ])
    , [ id ]
    )
    
const data =
  { 0 : [ 1, 2, 3 ]
  , 1 : [ 11, 12, 13 ]
  , 2 : [ 21, 22, 23 ]
  , 3 : [ 31, 32, 33 ]
  , 11 : [ 111, 112, 113 ]
  , 33 : [ 333 ]
  , 333 : [ 3333 ]
  }

traverse (0) .then (console.log, console.error)
// => Promise
// ~2 seconds later
// [ 0, 1, 11, 111, 112, 113, 12, 13, 2, 21, 22, 23, 3, 31, 32, 33, 333, 3333 ]

这篇关于如何取消这些承诺的嵌套?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆