gpt4 book ai didi

javascript - 如何取消嵌套这些 Promise?

转载 作者:行者123 更新时间:2023-11-29 18:50:46 25 4
gpt4 key购买 nike

背景

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

为了实现这一点,我有以下代码:

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 } ) )
);

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

问题?

我遇到的问题是我的 catch 里面有一个 Promise,这意味着我有嵌套。现在,我强烈反对嵌套 promise ,所以我真的很想摆脱它,但我不知道该怎么做。

问题

  1. 是否有可能摆脱 catch 中的嵌套 promise ?
  2. 如果是怎么办?

最佳答案

Problem?

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

问题是你认为你有问题——或者你把这个问题发布到 StackOverflow 而不是 CodeReview . article you linked显示您对嵌套 promise 的幼稚看法

You get a whole bundle of promises nested in eachother:

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

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.

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

– Code Monkey, http://taoofcode.net

不,Promise.all 只能有时 替换嵌套的 promise。一个简单的反例 - 在这里,一个 promise 的值取决于另一个,因此这两个必须被排序

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

嵌套 promises 并非总是必要的,但称其为“反模式”并鼓励人们在知道差异有害之前避免使用它,imo。


语句不起作用

other linked article显示您可能再次被误导的地方

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.

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

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

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

或者如果我们尝试在另一个表达式中间使用 if

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

那是因为 if 是一个语句,它永远不会计算出一个值——相反,它只能依赖于副作用。

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

for 下永远不会计算出一个值。相反,它依靠副作用来计算 sum

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

对于 dowhileswitch,甚至 return 和所有其他命令也是如此关键字 – 它们都是语句,因此依赖于副作用来计算值。

那么什么计算出一个值呢? 表达式求值

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

asyncawait 不是语句

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

const f = async x => ...

或者你可以传递一个异步函数作为参数

someFunc (async x => ... )

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

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

你可以等待一个值并将它赋给一个变量

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

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

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

因为 async/await 形成了 expressions ,所以它们可以与函数式风格一起使用。如果您正在尝试学习函数式风格并避免使用 asyncawait,那只是因为您被误导了。如果 asyncawait 只是命令式风格,那么这样的事情将永远不可能发生

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

实例

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

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 位于您和您的数据之间。您如何查询一个节点及其所有后代?

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 的话来说。它是使用函数表达式编写的,错误会相应地冒出来,我们甚至不必触摸 .then

我们可以使用命令式风格编写相同的程序。或者我们也可以使用 .then 来编写它的函数式风格。我们可以用各种方式来编写它,我想这就是重点——感谢 asyncawait 形成表达式的能力,我们可以以各种风格使用它们,包括功能风格。

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

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 ]

关于javascript - 如何取消嵌套这些 Promise?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51377172/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com