如何在JavaScript中实现异步函数之间的依赖关系?
作为一个简化的例子,我有两个异步函数,如何在JavaScript中实现异步函数之间的依赖关系?,javascript,jquery,asynchronous,dependencies,deferred,Javascript,Jquery,Asynchronous,Dependencies,Deferred,作为一个简化的例子,我有两个异步函数,foo和barbar需要foo的结果,即bar取决于foo。我不知道将首先调用哪个函数 如果首先调用bar,bar将调用foo,并在foo完成后立即启动 如果首先调用foo,然后执行,bar可以使用foo的结果 如果先调用foo,然后在foo完成之前调用bar,bar需要等待foo的结果。(不要调用对foo的新调用,只需等待已触发的对foo的调用) 我如何才能做到这一点? 是否可以注册异步函数依赖关系链(类似于require.jsdefine['foo'],
foo
和bar
bar
需要foo
的结果,即bar
取决于foo
。我不知道将首先调用哪个函数
bar
,bar
将调用foo
,并在foo
完成后立即启动foo
,然后执行,bar
可以使用foo
的结果foo
,然后在foo
完成之前调用bar
,bar
需要等待foo
的结果。(不要调用对foo
的新调用,只需等待已触发的对foo
的调用)是否可以注册异步函数依赖关系链(类似于require.js
define['foo'],function(){bar();}
)中的依赖关系?我可以使用
$.deferred()
来实现它吗?怎么做 您可以简单地认为这两个函数是独立的。这样,就不会对异步运行的依赖项进行菊花链。然后,您可以使用另一个模块 <>因为他们做了一些事情,考虑使用承诺。为了兼容性,可以使用jQuery的延迟。将延迟视为读/写,而承诺是只读的
// foo.js
define(function(){
return function(){
return new Promise(function(resolve, reject){
// Do async stuff. Call resolve/reject accordingly
});
};
});
// bar.js
define(function(){
return function(){
return new Promise(function(resolve, reject){
// Do async stuff. Call resolve/reject accordingly
});
};
});
// Your code (Excuse the CommonJS format. Personal preference)
define(function(require){
// Require both functions
var foo = require('foo');
var bar = require('bar');
// Use them
foo(...).then(function(response){
return bar();
}).then(function(){
// all done
});;
});
在这种情况下,标准方法是缓存较低级别的承诺 通常,您将在某个合适的外部作用域中建立一个js普通对象作为承诺缓存,并在调用异步进程之前始终首先查看该对象
var promiseCache = {};
function foo() {
if(!promiseCache.foo) {
promiseCache.foo = doSomethingAsync();
}
return promiseCache.foo;
}
function bar() {
return foo().then(doSomethingElseAsync);
}
当然,如果合适的话,也没有什么可以阻止您缓存更高级别的承诺
function bar() {
if(!promiseCache.bar) {
promiseCache.bar = foo().then(doSomethingElseAsync);
}
return promiseCache.bar;
}
编辑:强制刷新
功能
通过传递(额外)参数,可以强制函数刷新其缓存承诺
function foo(any, number, of, other, arguments, forceRefresh) {
if(forceRefresh || !promiseCache.foo) {
promiseCache.foo = doSomethingAsync();
}
return promiseCache.foo;
}
通过使forceRefresh
成为最后一个参数,省略它与传递false
相同,foo
将使用缓存的承诺(如果可用)。或者,传递true
以保证调用doSomethingAsync()
并刷新缓存的值
编辑2:setName()/getName()
在getName()
中使用forceRefresh
机制时:
或者,省略forceRefresh
机制,并假设缓存属性为promiseCache.name
:
setName(newName).then(getName.bind(null, true)); //set new name then read it back using forceRefresh.
setName(newName).then(function() {
promiseCache.name = $.when(newName);//update the cache with a simulated `getName()` promise.
});
第一种方法更优雅,第二种方法更有效。尝试使用可能的值创建对象属性
undefined
,“pending”
,true
;当obj.active
为true
时调用deferred.resolve()
,obj.active
为“挂起”时调用deferred.reject()
var res={
活动:无效0
};
var foo=函数foo(状态){
变量t;
var deferred=函数(类型){
返回延迟的美元(函数(dfd){
如果(res.active==“pending”| | state&&state==“pending”){
res.active=“待定”;
dfd.rejectWith(res,[res.active])
}否则{
res.active=状态| |“待定”;
t=设置间隔(函数(){
console.log(res.active)
}, 100);
setTimeout(函数(){
净间隔(t)
res.active=true;
dfd.resolveWith(res,[res.active])
}, 3000);
}
返回dfd.promise()
})
.then(功能(状态){
日志(“foo值”,状态);
返回状态
},函数(err){
日志(“foo状态”,err)
返回错误
})
}
返回延迟()
}
变量栏=功能栏(结果){
var deferred=函数(类型){
返回延迟的美元(函数(dfd){
if(结果&&result==true){
setTimeout(函数(){
dfd.resolveWith(结果,[true])
}, 1500)
}否则{
dfd.rejectWith(res[res.active | | |“pending”]))
};
返回dfd.promise()
})
}
return deferred().then(函数(数据){
console.log(“条值”,数据);
},函数(err){
控制台日志(“条形图状态”,错误);
})
}
$(“按钮”)。单击(函数(){
$(this).is(“:first”)
?foo()。然后(巴,巴)
:bar(res.active==true?res.active:“待定”)
然后(foo,foo),然后(bar,bar)
})
福
bar
我不确定我是否正确理解了这个问题。但我的看法是:
- 将函数foo放入变量中
var foo\u fn=function foo(foo\u args){//异步代码在这里}
- foo是异步的,并在某个点返回某些内容。在您对foo的定义中,我建议您使用promissions,该概念旨在以干净且可伸缩的方式管理异步函数的组合。这个概念的jQuery实现在许多简单的用例中都很方便,但也有一些缺点,这使得您在某些时候使用遵循promises/a规范的众多promises库中的一个很有意思。有关更多信息,请参阅: 比照及
- 因此,假设foo接受args,并返回一个承诺,该承诺随后解析为某个值
这里我使用RSVP承诺库,但是任何遵循承诺/A规范的承诺库都可以完成这项工作var foo\u fn=函数foo(foo\u args){ return foo_fn.promise=新的RSVP.promise(解析,拒绝){
//异步代码在这里 } } - 调用bar时,您只需执行以下操作:
功能条(条参数){ var foo_promise=foo_fn.promise; //如果调用了foo,无论计算正在进行还是已完成, //foo_fn.promise字段将不为空,因为foo会立即返回 //随时都有承诺