有问题吗?
我的问题是我的捕获物里面有一个承诺,这意味着我有巢穴。现在,我强烈反对嵌套的承诺,所以我真的想摆脱它,但我不知道怎么做。
火焰凤凰
问题是你认为你有问题,或者你把这个问题贴在stackoverflow上,而不是
CodeReview
. 这个
article you linked
显示在何处对嵌套的承诺采用幼稚的观点
你会得到一大堆相互嵌套的承诺:
loadSomething().then(function(something) {
loadAnotherthing().then(function(another) {
DoSomethingOnThem(something, another);
});
});
之所以这样做,是因为您需要对这两个承诺的结果进行处理,因此您可以将它们串起来,因为then()只传递上一个返回的结果。
你这么做的真正原因是你不知道
Promise.all()
方法。
_“代码猴,
http://taoofcode.net
不,
Promise.all
只能
有时
替换嵌套的承诺。一个简单的反例是,一个承诺的价值取决于另一个承诺,因此这两个承诺
必须
按顺序排列
getAuthorByUsername (username) .then (a => getArticlesByAuthorId (a.id))
嵌套承诺不是
总是
有必要,但我认为这是一种“反模式”,鼓励人们在意识到这种差异是有害的之前避免它。
语句不起作用
这个
other linked article
显示你可能再次被误导的地方
别误会我,异步/等待不是世界上所有邪恶的源头。我用了几个月才学会喜欢它。因此,如果您觉得编写命令式代码很方便,那么学习如何使用Async/Wait来管理异步操作可能是一个不错的选择。
但是,如果您喜欢承诺,并且您喜欢学习并将越来越多的功能性编程原则应用到代码中,那么您可能希望完全跳过异步/等待代码,停止思考命令式编程,转而使用这个新的旧范式。
加布里埃尔·蒙特斯
只是这没有任何意义。如果您在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 (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
同样的道理也适用于
do
,
while
,
switch
甚至
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" ]
async
和
await
不是陈述
可以将异步函数赋给变量
const f = async x => ...
或者可以将异步函数作为参数传递
someFunc (async x => ... )
即使是一个
异步的
函数不返回任何值,
异步的
仍然保证我们会得到承诺的价值
const f = async () => {}
f () .then (() => console.log ("done"))
// "done"
你可以
等待
一个值并将其赋给一个变量
const items = await getItems () // [ ... ]
或者你可以
等待
另一表达式中的值
items .concat (await getMoreItems ()) // [ ... ]
这是因为
异步的
/
等待
形式
表达
它们可以与功能风格一起使用。如果你试图学习功能风格并避免
异步的
和
等待
因为你被误导了。如果
异步的
和
等待
如果只是命令式的话,这样的事情是不可能的
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
.
我们可以使用命令式编写相同的程序。或者我们可以用
然后
也是。我们可以用各种方式来写,我想这就是重点所在
异步的
和
等待
形成的能力
表达
我们可以在各种样式中使用它们,包括功能样式。
在下面的浏览器中运行整个程序
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 ]