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

问题描述:

我正在使用JavaScript API,其中大部分函数都是异步的。该API是WebKit JavaScript Database API,它是对操作SQLite3数据库的功能子集的绑定。我了解设计决策,使异步事件不会阻塞并提供响应式用户界面。在我的情况下,我知道我的异步API调用的使用将会很快执行。既然是这样的话,我想为我的开发人员提供一个更简洁,更易于使用的包装器API来强制同步调用。用于包装异步JavaScript函数以使其同步的模式

这里的异步调用

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

下面是想我能够做到

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

是否有设计模式/方式做到这一点?书面或链接到代码示例是首选。目标平台/浏览器是iPhone上的Mobile Safari。

谢谢

+0

这将是有趣的,看看如果你得到一个答案,因为我怀疑这只是不可能(至少不支持线程,其Safari浏览器是不会给你)。 – 2008-10-18 03:57:03

,如果你使用jQuery的Ajax: $。阿贾克斯()

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

+2

我看过他的方式jQuery通过使用异步布尔实现了$ .ajax()函数,但事实证明它只是将异步参数传递给在“本机”代码中实现的XMLHttpRequest.open函数(不是js),因此可以强制同步行为。 – pfeilbr 2008-10-18 17:58:16

我们正在使用GWT RPC,它也有一个异步API。我们目前正在使用,以使串行几个异步调用的解决方法是调用链接:

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

此嵌套方法实现你想要什么,但它很冗长,难以阅读的新人。一,我们已经调查是增加,我们需要对堆栈的调用,为了执行这些问题的办法的:

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

callStack.execute(); 

然后调用堆栈将管理:

  1. 调用串行来电(即第一个示例中的接线)
  2. 将来自一个呼叫的结果传递给下一个呼叫。

但是,由于Java没有函数引用,因此调用堆栈上的每个调用都需要一个匿名类,所以我们停止了这种解决方案。但是,您可能在JavaScript中获得更多成功。

祝你好运!

对不起,JavaScript不提供语言原语(如线程或协程)来使异步事件同步进行,反之亦然。

您通常*仅获得一个执行线程,因此您无法从计时器或XMLHttpRequest readystatechange获取回调,直到导致创建请求的调用堆栈完全解除为止。

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

*:除了这不会帮助你,一般被认为是错误

一些模糊的情况下
+1

这很有道理。感谢您的明确解释。 – pfeilbr 2008-10-18 18:00:10

+1

2014年更新,JavaScript现在包含处理此问题的语言原语(协同程序),但当前支持仅限于标记和Firefox下的NodeJS,Chrome。 https://github.com/petkaantonov/bluebird/blob/master/API.md#promisecoroutinegeneratorfunction-generatorfunction---function – 2014-04-11 07:25:38

你可以尝试这样的:

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

但是,这可能会冻结您的浏览器的时间异步方法...

或者看一看叙述性的JavaScript:叙述性的JavaScript是JavaScript语言的一个小扩展,它支持异步事件回调的阻塞功能。这使得异步代码更清晰易读并易于理解。

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

迈克

+3

JavaScript没有线程,这是行不通的。一旦`while'循环开始,它永远不会结束。 – naomik 2014-09-12 10:01:18

+0

你是对的,在几年后读我自己让我感觉有点愚蠢;) – 2014-09-12 11:05:07

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

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. 
    } 
} 

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

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

我不确定如果这是正确的地方,但我在这里搜索寻找在Firefox中进行同步呼叫的答案。解决方法是删除onreadystatechange回调并直接调用。 这是我的发现和我的解决方案 synchronous call back with rest service