在开发移动PhoneGap应用程序时,我遇到了一个有趣的问题。我需要从数据库中查询大约10项数据(通过PhoneGaps SQLite应用程序接口)……像很多javascript API一样,这个是异步的。当您进行查询时,您将传入一个“成功”处理程序。
现在,在这种情况下,我更倾向于使用同步查询方法,该方法仅在完成时返回。然后,我可以编写直线代码,逐个查询10个项目1。
由于PhoneGap的异步特性(实际上,我在整个JS中都看到了这一点),我被迫编写了一个看起来像这样的野兽:
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
}
}
}
}
}
而这只是我所需的深度的一半(并且大大简化了……)。当我在C中使用SQLite的时候,我可以简单地做一些类似的事情:
db.query( "SELECT...", resultA );
db.query( "SELECT...", resultB );
db.query( "SELECT...", resultC );
db.query( "SELECT...", resultD );
db.query( "SELECT...", resultE );
在我看来,当你只需深入1到2层时,成功处理程序方法是很好的……但是,当你需要更多的东西时,它就完全崩溃了。
它们是一个库,还是某个库的某个功能,可以让这一切变得更容易?
发布于 2011-12-19 18:34:04
这是一个在社区中非常普遍的问题,以至于出现了许多模式and libraries来解决它。
我最喜欢的是promises。我在一些活动中做了一个关于promises的演示,作为异步问题的解决方案;你可以在SlideShare:Callbacks, Promises, and Coroutines (oh my!): The Evolution of Asynchronicity in JavaScript上查看我的幻灯片。它还解释了为什么异步是必要的-简而言之,因为JavaScript是单线程的。
对于您给出的特定示例,请查看幻灯片53及其附近的内容。简而言之,假设db.query
返回了一个承诺,它将如下所示:
db.query("SELECT...")
.then(function (a) {
return db.query("SELECT..." + a);
})
.then(function (b) {
return db.query("SELECT..." + b);
})
.then(function (c) {
return db.query("SELECT..." + c);
})
.then(function (d) {
return db.query("SELECT..." + d);
})
.then(function (e) {
return db.query("SELECT..." + e);
});
当然,如果您不需要在下一个查询中使用一个查询的结果,那么它会变得更好:
Q.all([
db.query("SELECT..."),
db.query("SELECT..."),
db.query("SELECT..."),
db.query("SELECT..."),
db.query("SELECT...")
]).spread(function (a, b, c, d, e) {
// ...
});
发布于 2011-12-19 18:26:58
一种基本的简化方法是将查询放在列表中,并让相同的成功处理程序只需调用列表中的下一个查询即可。您需要持有一个指向当前正在执行的查询的指针,但它会更清晰地(至少从代码的外观上看)为您提供同步行为。
这将适用于任何闭包,因为您只需将列表值设置为一大堆代码,然后按顺序执行所有代码。
发布于 2011-12-19 18:34:14
如果只是嵌套让您困扰,那么只需按名称链接这些方法:
function success1() {
// do stuff to handle success
db.query("SELECT...", success2);
}
function success2() {
db.query("SELECT...", success3);
}
function success3() {
db.query("SELECT...", success4);
}
function success4() {
// do something
}
db.query("SELECT...", success1);
如果这些内部成功处理程序中的任何一个需要访问在其词法作用域中定义的内容,这将不起作用,但情况可能并非如此(即使是这样,您仍然可以将这些值作为参数传递给链中的下一个函数)。
https://stackoverflow.com/questions/8565638
复制