还记得 C++ 中的“const 中毒”,当你将一个方法标记为const
,然后你意识到你必须标记它调用的所有方法const
,然后标记它们调用的所有方法,等等?
我在Javascript中遇到了异步中毒问题,尽管我认为这无关紧要,尽管它是向上传播而不是向下传播。当一个函数可能调用一个异步函数时,它本身必须被重写为异步的,然后所有调用它的函数都必须是等等。
我在这里没有一个格式正确的问题(对不起,mods),但我希望有人有(a)建议或(b)可能有(a)的参考。
还记得 C++ 中的“const 中毒”,当你将一个方法标记为const
,然后你意识到你必须标记它调用的所有方法const
,然后标记它们调用的所有方法,等等?
我在Javascript中遇到了异步中毒问题,尽管我认为这无关紧要,尽管它是向上传播而不是向下传播。当一个函数可能调用一个异步函数时,它本身必须被重写为异步的,然后所有调用它的函数都必须是等等。
我在这里没有一个格式正确的问题(对不起,mods),但我希望有人有(a)建议或(b)可能有(a)的参考。
这不是一个坏问题。然而,有几种方法可以完全破坏你的控制流。注意:我没说它漂亮。
假设您有对象 A、B、C 和 D,A.Amethod
不返回任何内容并调用 B 的方法getBData
,B 调用getCData
C 的方法,问题是 C 调用 D 类似这样
var data = D.getRawData();
... something to be done with data ...
... something else to be done with data...
现在它必须写成
D.getData(function(data){
... something to be done with data ...
... something else to be done with data...
});
好吧,你总是可以为你的每个方法添加一个回调参数,这样对于代码,以前的代码看起来像:
var A = {
//I'm not recommending coding like this, just for demonstration purposes.
...
Amethod: function(x,y,z){
var somethingForA = this.B.getBData(1,2,3);
astatement1;
astatement2;
...
}
...
}
//end of A
...
var B = {
...
Bmethod: function(x,y,z){
var somethingForB = this.C.getCData(1,2,3);
bstatement1;
var somethingFromB = bstatement2;
return somethingFromB;
}
...
}
//end of B
...
var C = {
...
Cmethod: function(x,y,z){
var somethingForC = this.D.getRawData(1,2,3)
cstatement1;
var somethingFromC = cstatement2;
return somethingFromC;
}
...
}
//end of C
...
你现在有:
var A = {
...
Amethod: function(x,y,z){
this.B.getBData((1,2,3,function(somethingForA){
astatement1;
astatement2;
});
...
}
...
}
//end of A
...
var B = {
...
Bmethod: function(x,y,z,callback){
this.C.getCData(1,2,3,function(somethingForB){
bstatement1;
var somethingFromB = bstatement2;
callback(somethingFromB);
});
...
}
...
}
//end of B
...
var C = {
...
Cmethod: function(x,y,z,callback){
this.D.getRawData(1,2,3,function(somethingForC) {
cstatement1;
var somethingFromC = cstatement2;
callback(somethingFromC);
});
}
...
}
//end of C
...
这几乎是一个简单的重构,使用匿名函数来实现保持控制流的所有功能。我不知道那将是多么真实的转换。您可能需要对变量范围进行一些调整。显然,它不是那么漂亮。
还有其他方法吗?当然。如您所见,上面的代码很混乱,我们希望不要编写混乱的代码。混乱程度取决于上下文。
您不必传递回调参数,任何必要的回调都可以预先传递给对象,或者它可以作为参数中的一项传递。回调可能不需要直接调用,而是使用可用的各种事件处理方法之一间接调用(您必须查看您可能想要使用哪些库),并且可以在何时传入数据事件被触发。或者,也许有一个全局“DataGetter”,A 可以在“获取”数据时注册回调,以完全避开中介 B 和 C。
最后,需要考虑的是,如果您在调用中深陷其中只是为了发现您需要一些只能异步获得的东西,并且数据必须向上传递命令链,那么您可能会在以下方面做一些倒退的事情哪些对象应该控制程序逻辑的流程(不过,我真的很困惑如何描述为什么我认为这种情况是有问题的。)。我倾向于认为,由于 A 的实例必须包含 B 的实例,B 包含 C 的实例等,因此创建子实例作为其组合的一部分的实例应该对子实例的填充方式有一定程度的控制他们自己,而不是让子实例完全决定....如果这有意义:-(
在这一点上,我觉得我有点漫不经心……希望有人能比我更好地解释这些问题!
到目前为止我见过的最好的解决方案是promises。当然,所有发生的事情都是用异步中毒换取 Promise 中毒(因为任何依赖于 Promise 本身的计算都必须返回一个 Promise,但 Promise 比回调更灵活、更强大。
如果问题是 b() 应该阻塞直到完成但调用异步 a(),那么也许来自 a() 的回调可以设置一个标志,并且 b() 监视该标志。如果 a() 不提供回调,那么一旦 a() 完成,某处的值可能会发生变化。