我有一个changePassword函数返回一个promise:
function changePassword(userName, oldPassword, newPassword) {
return new Promise(
function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(ok) {
if (ok) resolve(); else reject();
}
});
}
我需要修改此函数,以便newPassword可以是值或promise:
// functionReturningNewPasswordValOrPromise is a function returning either a value
// or a promise that will resolve with a value
function changePassword(userName, oldPassword, functionReturningNewPasswordValOrPromise) {
return new Promise( ...
如果functionReturningNewPasswordValOrPromise返回一个值(新密码),则一切都按上述步骤进行。
但是,如果functionReturningNewPasswordValOrPromise返回一个promise,它将首先运行(即提示用户)。如果已解决(即使用新密码字符串),changePassword将继续使用该值进行解析。如果拒绝,changePassword本身将拒绝。
我知道我需要以某种方式使用Promise.resolve(thenable),但不知道如何继续。
THX!
(我需要在ES6中给出答案,以便我可以在IE中使用polyfill ..没有ES7)
答案 0 :(得分:2)
具有可能或不是承诺的值通常是反模式,然后尝试检查它们是什么,或者具有处理它的特殊逻辑,或者将它们转换为承诺。这同样适用于可能返回这样的可能 - 许诺 - 可能不是值的函数。
因此,我们需要返回调用函数的位置以及获取newPassword
参数的位置。让我们假设它是这样的,使用getNewPassword
函数,该函数目前被设计为返回值或承诺:
changePassword(userName, oldPassword, getNewPassword())
第一种也许是最好的方法是简单地改变getNewPassword
的定义,以便它总是返回一个承诺 - 即使它已经用某种值解决了。然后你可以把上面的内容写成
getNewPassword() .
then(newPassword => changePassword(userName, oldPassword, newPassword))
并且您根本不必更改changePassword
的原始定义。
即使您无法更改getNewPassword
的定义或签名,构建处理参数的逻辑似乎也很笨拙,该参数可能是也可能不是对changePassword
等特定接口的承诺。相反,我会在呼叫点通过
Promise.resolve(getNewPassword()) .
then(newPassword => changePassword(userName, oldPassword, newPassword))
换句话说,吸收getNewPassword
模糊设计的影响,而不是让下游的人担心它。
如果你真的想处理那些带有可能会或可能不会有承诺的参数的函数,你可以概括一下:
function promisify_arguments(fn) {
return function(...args) {
return Promise.all(args) . then(vals => fn(...vals));
};
}
如果由于某种原因你有承诺但没有ES6支持,那么在ES5中:
function promisify_arguments(fn) {
return function() {
return Promise.all(arguments) . then(function(vals) {
return fn.apply(0, vals));
});
};
}
这需要一个期望非承诺参数的函数,并返回一个修改过的函数,该函数可以通过对某些或所有参数的promise进行调用,并等待其所有的promise值参数解析,然后调用原始函数将值解析为参数,返回其值为结果值的promise。
您可以使用此功能将changePassword
功能转换为
var changePasswordWhereNewPasswordMayBePromise = promisify_arguments(changePassword);
然后使用changePasswordWhereNewPasswordMaybePromise
代替changePassword
。这具有潜在的优势,如果userName
或oldPassword
作为承诺提供,它将自动做正确的事。
答案 1 :(得分:2)
处理newPassword
作为密码或承诺的简单答案是:
function changePassword(userName, oldPassword, newPassword) {
return Promise.resolve(newPassword).then(password => new Promise((r, e) =>
someAsyncFunction(userName, oldPassword, password, ok => ok ? r() : e())));
}
当Promise.resolve(x)
是承诺(*)时, x
会返回x
,而当承诺x
时,承诺会以值Promise.resolve(p) === p
解析。
在其他答案中有很好的建议,但我相信这就是所要求的。
*)在大多数实现中,但不是全部(Safari是一个例外),当p
是一个承诺时,我发现test
test test
,但这是一个细节。重要的是它在这种情况下就像最初的承诺一样。
答案 2 :(得分:1)
我建议将someAsyncFunction包装成基于promise的函数。 e.g。
function someAsyncFunctionP(userName, oldPassword, newPassword) {
return new Promise(function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(err) {
if(err) reject(err); else resolve();
});
});
}
然后,为了让newPassword
成为一个承诺,你可以写下这个。
function changePassword(userName, oldPassword, newPassword) {
return Promise.resolve(newPassword).then(function(newPassword) {
return someAsyncFunctionP(userName, oldPassword, newPassword);
});
}
答案 3 :(得分:0)
function changePassword(userName, oldPassword, functionReturningNewPasswordValOrPromise) {
var getNewPassPromise=functionReturningNewPasswordValOrPromise(email);
return Promise.resolve(getNewPassPromise).then(function(newPassword) {
return changePasswordWithVal(email, oldPassword, newPassword);
});
}
// do the real work
function changePasswordWithVal(userName, oldPassword, newPassword) {
return new Promise(
function(resolve, reject) {
someAsyncFunction(userName, oldPassword, newPassword, function(ok) {
if (ok) resolve(); else reject();
}
});
}