如何避免这种异步惰性模式?
How to avoid this async lazy pattern?
很多时候,我需要在Javascript中写这样一个延迟异步加载:
if (myvar != undefined){
doSomeTreatment(myvar)
} else {
loadMyVarAsynchronously().then(function(value){
myvar = value
doSomeTreatment(myvar)
})
}
在这里,myvar 是散列的某个属性,而不是局部变量。 loadMyVarAsynchronously
异步加载 myvar 的值(例如,Promise
或 JQuery Deferred
)
是否有一种模式可以避免在此代码中将以下行写两次?
doSomeTreatment(myvar)
如果 myvar
已经定义,您可以将其传递给 $.when()
并自动将其包装到已解决的承诺中:
var def = (myVar !== undefined) ? myVar : loadMyVarAsynchronously();
$.when(def).then(doSomeTreatment);
如果需要,在 doSomeTreatment()
内部对 myVar
赋值,而不是在匿名 .then
回调内部,这允许您直接将 doSomeTreatment
作为函数传递参考。
编辑 哎呀,你想要标准的承诺,还是 jQuery 承诺?以上是jQuery风格。
是的,您应该为价值建立承诺。然后你只需要附加该函数一次作为处理程序:
var loadedMyVar = myvar!=undefined ? Promise.resolve(myvar) : loadMyVarAsynchronously();
loadedMyVar.then(doSomeTreatment);
哦,您不需要异步重新分配给 myvar
,只需在任何地方使用 loadedMyVar
承诺即可。甚至可以使用
var loadedMyVar = loadedMyVar || loadMyVarAsynchronously();
loadedMyVar.then(function(value) {
return myvar = value;
}).then(doSomeTreatment);
如果没有具体的真实示例,真的很难推断您在这里所做的事情。这绝对不是我在代码中经常使用的模式,因此我怀疑您可以通过重新评估您的假设来解决它。
也就是说,您可以使用承诺链。请注意,在这种情况下,promiseThatLoadsVar 是一个承诺,它不是 return 一个承诺的函数。这意味着它保持一个状态,并且这段代码第二次继续运行时它将立即return。
promisethatLoadsVar.then(function(value) {
myvar = value;
doSomeTreatment(myvar);
})
如果您能提出更明确的问题,我很乐意为您提供更明确的答案。
编辑:我想详细说明评论中提出的例子。这是使用 LoDash 库的解决方案。 (顺便说一句,你应该使用lodash或underscore,它们基本上是javascript的标准库)。
var getData = _.once(function() { return $.getJSON(...) });
$('button').on('click', function() {
getData().then(function(data) { showDialog(data) })
})
请注意,getData
是一个包装函数,在第一次调用后将只是 return 一遍又一遍地执行相同的操作,而无需重新调用该函数。第一次调用它时,它将 return 一个在检索数据时解析的承诺。第二次之后,您会得到 相同的承诺 ,它可能已经得到解决。
是否要给getData
传入参数?
var getData = _.memoize(function(id) { return $.getJSON(url+id) });
$('button').on('click', function() {
getData($('#selector').val()).then(function(data) { showDialog(data) })
})
这将做同样的事情,但通过传递给 getData
的第一个输入参数缓存承诺。
使用 myvar != undefined
检查是否检索它存在一个问题,那就是当您启动另一个检索时可能已经在进行检索。您最终会执行该请求两次(或更多次!)。
为避免这种情况,您可以坚持承诺,将其视为 myvar
的 未来价值 ,并且根本不使用 myvar
:
// assume myvarpromise is persisted somewhere longer than the
// life of this function
myvarpromise = myvarpromise || loadMyVarAsynchronously();
myvarpromise.then(doSomeTreatment);
很多时候,我需要在Javascript中写这样一个延迟异步加载:
if (myvar != undefined){
doSomeTreatment(myvar)
} else {
loadMyVarAsynchronously().then(function(value){
myvar = value
doSomeTreatment(myvar)
})
}
在这里,myvar 是散列的某个属性,而不是局部变量。 loadMyVarAsynchronously
异步加载 myvar 的值(例如,Promise
或 JQuery Deferred
)
是否有一种模式可以避免在此代码中将以下行写两次?
doSomeTreatment(myvar)
如果 myvar
已经定义,您可以将其传递给 $.when()
并自动将其包装到已解决的承诺中:
var def = (myVar !== undefined) ? myVar : loadMyVarAsynchronously();
$.when(def).then(doSomeTreatment);
如果需要,在 doSomeTreatment()
内部对 myVar
赋值,而不是在匿名 .then
回调内部,这允许您直接将 doSomeTreatment
作为函数传递参考。
编辑 哎呀,你想要标准的承诺,还是 jQuery 承诺?以上是jQuery风格。
是的,您应该为价值建立承诺。然后你只需要附加该函数一次作为处理程序:
var loadedMyVar = myvar!=undefined ? Promise.resolve(myvar) : loadMyVarAsynchronously();
loadedMyVar.then(doSomeTreatment);
哦,您不需要异步重新分配给 myvar
,只需在任何地方使用 loadedMyVar
承诺即可。甚至可以使用
var loadedMyVar = loadedMyVar || loadMyVarAsynchronously();
loadedMyVar.then(function(value) {
return myvar = value;
}).then(doSomeTreatment);
如果没有具体的真实示例,真的很难推断您在这里所做的事情。这绝对不是我在代码中经常使用的模式,因此我怀疑您可以通过重新评估您的假设来解决它。
也就是说,您可以使用承诺链。请注意,在这种情况下,promiseThatLoadsVar 是一个承诺,它不是 return 一个承诺的函数。这意味着它保持一个状态,并且这段代码第二次继续运行时它将立即return。
promisethatLoadsVar.then(function(value) {
myvar = value;
doSomeTreatment(myvar);
})
如果您能提出更明确的问题,我很乐意为您提供更明确的答案。
编辑:我想详细说明评论中提出的例子。这是使用 LoDash 库的解决方案。 (顺便说一句,你应该使用lodash或underscore,它们基本上是javascript的标准库)。
var getData = _.once(function() { return $.getJSON(...) });
$('button').on('click', function() {
getData().then(function(data) { showDialog(data) })
})
请注意,getData
是一个包装函数,在第一次调用后将只是 return 一遍又一遍地执行相同的操作,而无需重新调用该函数。第一次调用它时,它将 return 一个在检索数据时解析的承诺。第二次之后,您会得到 相同的承诺 ,它可能已经得到解决。
是否要给getData
传入参数?
var getData = _.memoize(function(id) { return $.getJSON(url+id) });
$('button').on('click', function() {
getData($('#selector').val()).then(function(data) { showDialog(data) })
})
这将做同样的事情,但通过传递给 getData
的第一个输入参数缓存承诺。
使用 myvar != undefined
检查是否检索它存在一个问题,那就是当您启动另一个检索时可能已经在进行检索。您最终会执行该请求两次(或更多次!)。
为避免这种情况,您可以坚持承诺,将其视为 myvar
的 未来价值 ,并且根本不使用 myvar
:
// assume myvarpromise is persisted somewhere longer than the
// life of this function
myvarpromise = myvarpromise || loadMyVarAsynchronously();
myvarpromise.then(doSomeTreatment);