我看到Handling multiple catches in promise chain中的promise实现产生了一个非常易读的链
return validateInput
.then(checkLoginPermission)
.then(checkDisableUser)
.then(changePassword);
但是,为了做到这一点,每个函数都需要返回一个值而不是一个Promise?因为Promise可以解析为值或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
...
}
当链中的最后一个函数从一开始就依赖某些东西时,情况会更糟。这意味着即使没有使用,该值也必须从链的开头传递下来。
所以我不小心踩到某种可能影响性能的反模式?如果没有这些麻烦,我怎样才能获得良好的可读性?
答案 0 :(得分: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,我通常会使用你的第二个代码片段,或者在ontop上定义更高范围的变量:
let resultA
return validateInput
.then(function(result) {
resultA = result
return checkLoginPermission
.then (function(resultB) {
// Do something with resultA
})
});
答案 1 :(得分:1)
Promise是与函数式编程相关的模式,从一个函数到另一个函数的直接传递数据是基本的(它被称为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之前声明的某个变量中收集数据,因此您不必传递结果。但它会破坏Promises的功能性。
答案 2 :(得分:0)
内部.then(/* ... */)
回调可以返回原始值或解析为某个值的Promise。如果它是另一个承诺,则下一个承诺。然后才开始直到内部承诺得到解决。从本质上讲,Promises总是解析为非承诺类型。如果您解决或返回另一个Promise,它将自动解包。
答案 3 :(得分:0)
我想使用ramda.js#pipeP()提出解决方案。
这个功能的好处在于它能够顺序解决承诺。
我们可以使用pipeP()
重写您的示例:
import pipeP from 'ramda/src/pipeP'
pipeP([
checkLoginPermission,
checkDisableUser,
changePassword
])(initialValue)
.then(responseChangePassword => { ... })
先前承诺的结果将传递给下一个承诺。