假设您想在JavaScript中创建异步请求,但是您希望将某些状态传递给回调方法。以下是否适当使用JavaScript中的闭包?
function getSomethingAsync(someState, callback) {
var req = abc.createRequestObject(someParams);
req.invoke(makeCallback(someState, callback));
}
function makeCallback(someState, callback) {
return function getSomethingCallback(data) {
var result = processDataUsingState(data, someState);
callback(result); // alternately/optionally pass someState along to result
}
}
如果没有,是否有更好或更惯用的方式?
答案 0 :(得分:2)
我没有看到任何直接的问题 - 闭包功能强大有很多原因,其中一个原因是不需要使用全局变量进行状态维护。
也就是说,关于闭包,你唯一需要警惕的是内存泄漏,这通常发生在IE中,但那些通常是IIRC,与DOM元素和附加的事件处理程序有关。
继续!
答案 1 :(得分:1)
更惯用的方法是使用Function.bind
,然后您不需要复制代码来创建闭包。我将使用一个简单的例子(没有你的自定义代码)来解释
/**
* Retrieves the content of a url asyunchronously
* The callback will be called with one parameter: the html retrieved
*/
function getUrl(url, callback) {
$.ajax({url: url, success: function(data) {
callback(data);
}})
}
// Now lets' call getUrl twice, specifying the same
// callback but a different id will be passed to each
function updateHtml(id, html) {
$('#' + id).html(html);
}
// By calling bind on the callback, updateHTML will be called with
// the parameters you passed to it, plus the parameters that are used
// when the callback is actually called (inside )
// The first parameter is the context (this) to use, since we don't care,
// I'm passing in window since it's the default context
getUrl('/get/something.html', updateHTML.bind(window, 'node1'));
// results in updateHTML('node1', 'response HTML here') being called
getUrl('/get/something-else.html', updateHTML.bind(window, 'node2'));
// results in updateHTML('node2', 'response HTML here') being called
Function.bind
是新的,所以如果您需要向后支持,请查看Function.bind
的兼容性部分
最后,我知道这个问题没有被标记为jQuery。这是在不处理跨浏览器问题的情况下显示异步函数的最快方法
答案 2 :(得分:0)
使用匿名函数更好(更好):
function getSomethingAsync (someState, callback) {
req.invoke (function (data) {
var result = processDataUsingState (data, someState);
callback (result);
});
}
答案 3 :(得分:0)
您还可以使用call()/ apply()在函数中操作“this”的值。
例如,指定异步方法的另一个参数是在回调中用作“this”的对象。这就是jQuery如何在事件回调中将dom节点设置为“this”。
function getSomethingAsync(callback, scope) {
var req = abc.createRequestObject(someParams);
req.invoke(function(rsp) {
callback.apply(scope, [rsp]);
});
}
// usage:
getSomethingAsync(function() {console.log(this.someState)}, {someState:'value'});