很多时候,我需要在Javascript中编写这样一个懒惰的异步加载:
if (myvar != undefined){
doSomeTreatment(myvar)
} else {
loadMyVarAsynchronously().then(function(value){
myvar = value
doSomeTreatment(myvar)
})
}
这里,myvar是哈希的一些属性,而不是局部变量。 loadMyVarAsynchronously
异步加载myvar的值(例如,使用Promise
或JQuery Deferred
)
是否有一种模式可以避免在此代码中写入以下两行?
doSomeTreatment(myvar)
答案 0 :(得分:2)
如果已定义myvar
,您可以将其传递到$.when()
并将其自动包装到已解决的承诺中:
var def = (myVar !== undefined) ? myVar : loadMyVarAsynchronously();
$.when(def).then(doSomeTreatment);
如果需要,在myVar
内doSomeTreatment()
进行分配,而不是在匿名.then
回调内,这样您就可以直接将doSomeTreatment
作为函数引用传递。
编辑 oops,你想要标准的Promises还是jQuery的承诺?以上是jQuery风格。
答案 1 :(得分:1)
是的,你应该建立一个价值承诺。然后你只需要将该函数作为处理程序附加一次:
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);
答案 2 :(得分:1)
如果没有一个具体的,现实世界的例子,你很难在这里做出正确的理由。这绝对不是我在代码中使用的模式,所以我怀疑你可以通过重新评估你的假设来解决这个问题。
话虽如此,你可以使用承诺链。请注意,在这种情况下,promiseThatLoadsVar是一个承诺,它不是一个返回承诺的函数。这意味着它维持一个状态,并且第二次该代码向前运行时它将立即返回。
promisethatLoadsVar.then(function(value) {
myvar = value;
doSomeTreatment(myvar);
})
如果您能提出更明确的问题,我很乐意为您提供更清晰的答案。
修改:我想详细说明评论中提出的示例。这是使用LoDash库的解决方案。 (顺便说一句,你应该使用lodash或下划线,它们基本上是javascript的标准库。)
var getData = _.once(function() { return $.getJSON(...) });
$('button').on('click', function() {
getData().then(function(data) { showDialog(data) })
})
请注意,getData
是一个包装函数,在第一次调用之后,只需反复返回相同的内容而不重新调用该函数。第一次调用它时,它将返回一个在检索数据时解析的promise。第二次你会得到相同的承诺,这可能已经解决了。
是否要将参数传递给getData
?
var getData = _.memoize(function(id) { return $.getJSON(url+id) });
$('button').on('click', function() {
getData($('#selector').val()).then(function(data) { showDialog(data) })
})
这将做同样的事情,但是通过传递给getData
的第一个输入参数来缓存promises。
答案 3 :(得分:1)
使用myvar != undefined
检查是否检索它是一个问题,那就是当你启动另一个时,可能已经有一个正在检索的检索。你最终会执行两次(或更多!)的请求。
为了避免这种情况,您可以保留承诺,将其视为myvar
的未来值,而不是myvar
:
// assume myvarpromise is persisted somewhere longer than the
// life of this function
myvarpromise = myvarpromise || loadMyVarAsynchronously();
myvarpromise.then(doSomeTreatment);