我可能在寻找一些不可能的东西,但无论如何,让我们试一试。请考虑下面的伪代码,它正在执行一些有条件的远程操作,并在完成后执行回调。但是回调中的代码需要执行,即使不需要远程操作:
if (needsToSave)
{
performRemoteOperation(operationParameters, function() {
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
});
}
else
{
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
我发现这个代码特别难看而且难以管理。在相关的无条件块中,很容易省略对回调块所做的更改。有一个明显的解决方案可以在一些命名函数中包装代码,但它不再是匿名内联代码。:-)
我能想到的最好的方法是将整个代码封装在某个条件调用程序中:
function conditionalCall(condition, action, callback)
{
if (condition)
action(callback)
else
callback()
}
然后我的代码会折叠为:
conditionalCall(needsToSave,
function(_callback) {
performRemoteOperation(operationParameters, _callback)
},
function()
{
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
);
但我不完全确定这是否更可读和更易于管理。特别是当涉及大量本地/远程/回调参数/闭包变量时,或者需要将一个远程调用"嵌入"到另一个调用的回调中时。我希望在这样的场景中可以使用一些更好的语法。
In可以简化为:
var finallyFunction = function {
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
if (needsToSave)
performRemoteOperation(operationParameters, finallyFunction);
else
finallyFunction();
这并不是一个真正的闭包问题。假设"远程操作"的意思是"异步操作",那么它就是处理异步响应。
当然,在这种情况下可以(通常也会)使用匿名函数,但请记住,"匿名函数"是,而不是"闭包"的同义词。忘记(几乎)你在PHP中学到的所有东西,这不是一个很好的词汇闭包学习基地。
如果我的假设是正确的,并且我们确实在谈论异步性,那么jQuery的Deferreds/promise提供了一个相当巧妙的解决方案。
// First make sure performRemoteOperation() returns a promise,
function performRemoteOperation(operationParameters) {
...
return promise;//for example a jqXHR object, as generated by $.ajax() and its shorthand methods.
}
function myFunction(needsToSave) {
var p = needsToSave ? performRemoteOperation(operationParameters) : $.Deferred.resolve().promise();
//At this point `p` is either an unresolved promise returned by performRemoteOperation(), or a resolved promise generated in the line above.
p.done(function() {
//This function fires when the remote operation successfully completes, or immediately if `needsToSave` was false.
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
});
return p;//A promise is returned for good measure, in case further chaining is necessary where myFunction() is called.
}
//Sample calls
myFunction(false);
myFunction(true).then(function() {
alert("successfully saved");
}, function() {
alert("error: something went wrong");
});
当然,如果您愿意,您可以将代码重构为一个函数,但可以说,将其理解为两个函数更容易,如问题所示。