用于包装异步JavaScript函数以使其同步的模式

Pattern for wrapping an Asynchronous JavaScript function to make it synchronous

本文关键字:同步 模式 包装 异步 JavaScript 函数 用于      更新时间:2023-09-26

我使用的是JavaScript API,其中大多数函数都是异步的。API是WebKit JavaScript数据库API,它绑定到操作SQLite3数据库的功能子集。我理解设计决策,使事情异步,从而不阻塞并提供响应用户界面。在我的情况下,我知道我对异步API调用的使用会执行得很快。既然是这种情况,我想为我的开发人员提供一个更干净、更容易使用的包装器API,强制同步调用。

这是异步调用

db.executeSql(sqlStatement, function(result) {
  // do something with result
});

以下是我想做的

var result = dbWrapper.executeSql(sqlStatement);
// do something with result

有没有设计模式/方法可以做到这一点?最好是编写或链接到代码的示例。目标平台/浏览器是iPhone上的Mobile Safari。

感谢

抱歉,JavaScript没有提供语言原语(例如线程或协程)来使异步事物同步运行,反之亦然。

您通常只获得一个执行线程,因此在导致创建请求的调用堆栈完全分解之前,您无法从计时器或XMLHttpRequest readystatechange获得回调。

简而言之,你不可能真正做到这一点;在您链接的WebKit页面上使用嵌套闭包的方法是我所知道的在这种情况下使代码可读的唯一方法。

*:除了在一些对你没有帮助的模糊情况下,通常被认为是错误

StratifiedJS允许您做到这一点。

甚至还有一篇关于如何将其应用于浏览器存储的文章:http://onilabs.com/blog/stratifying-asynchronous-storage

这是它使用的分层JavaScript库https://gist.github.com/613526

示例如下:

var db = require("webdatabase").openDatabase("CandyDB", ...);
try {
  var kids = db.executeSql("SELECT * FROM kids").rows;
  db.executeSql("INSERT INTO kids (name) VALUES (:name);", [kids[0]]);
  alert("done");
} catch(e) {
  alert("something went wrong");
}

也许有点晚了,但当时这项技术还不存在;)

您可以尝试以下操作:

function synch()
{
    var done = false;
    var returnVal = undefined;
    // asynch takes a callback method
    // that is called when done
    asynch(function(data) {
        returnVal = data;
        done = true;
    });
    while (done == false) {};
    return returnVal;
}

但这可能会在异步方法期间冻结您的浏览器。。。

或者看看Narrative JavaScript:Narrative JavaScript是JavaScript语言的一个小扩展,它支持异步事件回调的阻塞功能。这使得异步代码具有令人耳目一新的可读性和可理解性

http://neilmix.com/narrativejs/doc/index.html

Mike

如果您使用的是jQuery Ajax:$.ajax()

您可以将asynch的属性设置为false,然后您将有一个到服务器的同步ajax请求。

我们使用GWT RPC,它也有一个异步API。我们目前用于串行进行几个异步调用的解决方案是调用链:

callA(function(resultA) {
    callB(resultA, function(resultB) {
        callC(); //etc.
    });
});

这种嵌套方法实现了您想要的内容,但对于新手来说,它冗长且难以阅读。我们研究的方法之一是将我们需要进行的调用添加到堆栈中,并按顺序执行:

callStack = [
    callA(),
    callB(),
    callC()
];
callStack.execute();

然后调用堆栈将管理:

  1. 调用串行调用(即第一个示例中的布线)
  2. 将结果从一个调用传递到下一个调用

然而,由于Java没有函数引用,调用堆栈上的每个调用都需要一个匿名类,所以我们没有这样的解决方案。然而,您可能会在javascript方面取得更大的成功。

祝你好运!

这实际上并没有实现数据库查询的同步操作,但这是我的简单管理解决方案。基本上将调用函数用作回调函数,并测试results参数。如果函数接收到结果,它会解析它们;如果没有,它会将自己作为回调发送到查询方法。

 render: function(queryResults){
  if (typeof queryResults != 'undefined'){
   console.log('Query completed!');
   //do what you will with the results (check for query errors here)
  } else {
   console.log('Beginning query...');
   this.db.read(this.render); //db.read is my wrapper method for the sql db, and I'm sending this render method as the callback.
  }
 }

我不确定这是否是正确的地方,但我在这里搜索在Firefox中进行同步调用的答案。解决方案是删除onreadystatechange回调并直接调用。这就是我的发现和解决方案与休息服务的同步回调