具有可读函数名称的扁平化承诺链
Posted
技术标签:
【中文标题】具有可读函数名称的扁平化承诺链【英文标题】:Flattening promise chain with readable function name 【发布时间】:2017-09-29 03:18:04 【问题描述】:我在Handling multiple catches in promise chain 中看到了 Promise 实现,它产生了一个可读性很强的链
return validateInput
.then(checkLoginPermission)
.then(checkDisableUser)
.then(changePassword);
然而,为了做到这一点,每个函数都需要返回一个值而不是一个 Promise?由于 Promise 可以解析为 value 或 Promise,所以这不是问题。我的目标是让每个函数都具有可读清晰的逻辑。
尝试展开嵌套的promise函数时出现问题
return validateInput
.then(function(resultA)
return checkLoginPermission
.then (function(resultB)
// Do something with resultA
)
);
想象一下最初的实现涉及访问来自先前承诺的值。使用嵌套承诺,它很容易实现。但是使用扁平链,我需要像这样分解每个函数
function validateInput = function (resultA )
return Promise.resolve(resultA : resultA, resultB :
function checkLoginPermission = function (mix )
let resultA = mix.resultA;
let resultB = mix.resultB
//Do something with resultA
...
当链中的最后一个函数从一开始就依赖某些东西时,情况会更糟。这意味着该值必须从链的开头向下传递,即使它没有被使用。
那么我是否不小心踩到了某种可能影响性能的反模式?如果没有这些麻烦,我还能如何获得良好的可读性?
【问题讨论】:
【参考方案1】:我想提出一个使用ramda.js#pipeP()的解决方案。
这个函数的好处是它按顺序解析promise。
我们可以使用pipeP()
重写您的示例:
import pipeP from 'ramda/src/pipeP'
pipeP([
checkLoginPermission,
checkDisableUser,
changePassword
])(initialValue)
.then(responseChangePassword => ... )
前一个 promise 的结果被传递给下一个。
【讨论】:
【参考方案2】:内部.then(/* ... */)
回调可以返回原始值或解析为某个值的 Promise。如果它是另一个承诺,那么下一个 .then 在内部承诺解决之前不会开始。本质上,Promises 总是解析为非 Promise 类型。如果你解析或返回另一个 Promise,它将自动解包。
【讨论】:
【参考方案3】:Promises 是模式,与函数式编程相关,直接将数据从一个函数传递到另一个函数是基本的(称为compose
,此处示例:http://scott.sauyet.com/javascript/Talk/Compose/2013-05-22/)。所以它绝不是反模式。
我看不出这种模式有什么问题。您可以将任何您想要的数据传递给下一个 Promises,并在嵌套的 Promises 中获取他们需要的数据。它非常透明和清晰:
function validateInput()
return Promise.resolve(resultA: 1);
function checkLoginPermission(result)
return new Promise(function(resolve, reject)
// ...
// code
// ...
result.resultB = 2;
return resolve(result);
);
function checkDisableUser(result)
return new Promise(function(resolve, reject)
// grab some data from previous function
let resultB = result.resultB;
// ...
// code
// ...
result.resultC = 3;
return resolve(result);
);
function changePassword(result)
return new Promise(function(resolve, reject)
// grab some data from previous functions
let resultB = result.resultB;
let resultC = result.resultC;
// ...
// code
// ...
result.resultD = resultB * resultC;
return resolve(result);
);
validateInput()
.then(checkLoginPermission)
.then(checkDisableUser)
.then(changePassword);
您还可以在一些变量中收集数据,在 Promises 之前声明,因此您不必传递结果。但它会破坏 Promise 的功能性。
【讨论】:
但请注意explicit construction anti-pattern.... 这是一个非常巧妙的解决方案。为什么我没有想过只做一个累积的对象。【参考方案4】:这实际上是 async
和 await
的用武之地。当您需要跨多个异步调用/承诺的结果在范围内时,这很好。如果你能用,我会说试试看。
async function foo ()
const input = await validateInput()
const hasPermission = await checkLoginPermission(input)
const result = await checkDisableUser(hasPermission)
return await changePassword(result)
只需将变量传递给需要的函数即可。只是在那里展示一个例子。我也有点不确定您如何设置 validateInput,我认为您需要将 await
放在函数调用本身的前面。
如果您不能使用 async/await,我通常会使用您的第二个代码 sn-p,或者在顶部定义更高范围的变量:
let resultA
return validateInput
.then(function(result)
resultA = result
return checkLoginPermission
.then (function(resultB)
// Do something with resultA
)
);
【讨论】:
嘿,谢谢。是的,我在 async await 上读到了一点。虽然我更热衷于使用产量/生成器。你有什么想法吗?我正在使用 NodeJs 作为服务器 对不起,我没有。对 async/await 自己还是很陌生! 最后我使用 async/await!太好了!谢谢以上是关于具有可读函数名称的扁平化承诺链的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode——430. 扁平化多级双向链表(Java)
数据结构与算法之深入解析“扁平化多级双向链表”的求解思路与算法示例
LeetCode - 430 - 扁平化多级双向链表 - Java - 细喔
LeetCode 430. 扁平化多级双向链表 / 583. 两个字符串的删除操作 / 478. 在圆内随机生成点(拒绝采样圆形面积推导)