在javascript中获取同步行为?

时间:2011-12-19 18:22:34

标签: javascript asynchronous

在开发移动PhoneGap应用程序时,我遇到了一个有趣的问题。我需要从数据库中查询大约10项数据(通过PhoneGaps SQLite API)...像许多javascript API一样,这个是异步的。在进行查询时,您将传入“成功”处理程序。

现在,我在这种情况下的偏好是一个同步查询方法,只有在完成时才会返回。然后我就可以编写直线代码,一个接一个地查询10个项目中的每个项目。

由于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级时,成功处理程序的方法很棒...但是,当你需要更多时,完全崩溃......

他们的图书馆或图书馆的某个功能是否更容易?

4 个答案:

答案 0 :(得分:7)

这是一个在社区中非常普遍的问题,因此出现了许多模式and libraries来对抗它。

我最喜欢的是承诺。我做了一个关于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) {
  // ...
});

答案 1 :(得分:3)

一个基本的简化是将查询放在一个列表中并使用相同的成功处理程序简单地调用列表中的下一个查询。你需要保持一个指向当前正在执行的查询的指针,但它会更干净(至少从代码看起来如何)给你同步行为。

这适用于任何闭包,因为您只需将列表值设置为一堆代码块,然后按顺序执行所有这些操作。

答案 2 :(得分:3)

如果它只是困扰你的嵌套,只需按名称链接方法:

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);

如果任何内部成功处理程序需要访问其词法作用域中定义的内容,这将不起作用,但情况可能并非如此(即使它是,您仍然可以将这些值作为参数传递给链中的下一个功能)。

答案 3 :(得分:1)

有一个开源框架称为Siminov Hybrid,它为Native(Java)和Web(JavaScript)提供ORM。通过使用它,您可以使所有数据库操作同步,因为此框架使用Android提供的通信通道,即Synchronous。

将PhoneGap与此框架集成非常容易。使用此功能,您可以同时使用Native ORM和Web ORM。

http://siminov.github.io/android-hybrid