【问题标题】:Pattern for wrapping an Asynchronous JavaScript function to make it synchronous包装异步 JavaScript 函数以使其同步的模式
【发布时间】:2008-10-18 03:28:55
【问题描述】:

我正在使用 JavaScript API,其中大多数函数都是异步的。 API 是WebKit JavaScript Database 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。

谢谢

【问题讨论】:

  • 看看你是否得到答案会很有趣,因为我怀疑这是不可能的(至少没有线程支持,Safari 不会给你)。

标签: javascript iphone design-patterns safari mobile-safari


【解决方案1】:

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

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

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

*:除非在一些对你没有帮助并且通常被认为是错误的晦涩情况下

【讨论】:

【解决方案2】:

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

可能有点晚了,但当时技术还不存在;)

【讨论】:

    【解决方案3】:

    你可以试试这样的:

    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

    迈克

    【讨论】:

    • JavaScript 没有线程,这永远不会工作。 while 循环一旦启动,就永远不会结束。
    • 你说得对,几年后读自己的书让我觉得有点笨;)
    • 不要因此而自责。在我自己尝试之前,我实际上认为这也可以工作^.^
    • 哈哈,试着在 2017 年 1 月左右阅读这些答案。令人着迷。
    • @sweaver2112 是的,我不敢相信我写了那个!不过,你怎么又来这里了;)
    【解决方案4】:

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

    您可以将 asynch 的属性设置为 false , 然后您将向服务器发出同步 ajax 请求。

    【讨论】:

    • 我确实看过 jQuery 使用异步布尔值实现它的 $.ajax() 函数的方式,但事实证明它只是将异步参数传递给 XMLHttpRequest.open 函数在“本机”代码(不是 js)中实现,因此可以强制同步行为。
    【解决方案5】:

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

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

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

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

    然后调用堆栈将管理:

    1. 串行调用调用(即第一个示例中的接线)
    2. 将结果从一个呼叫转发到下一个。

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

    祝你好运!

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

      • 你不妨有一个单独的回调函数。使调用者函数也成为回调函数只是混淆了情况
      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        • 2012-10-15
        • 1970-01-01
        • 2012-02-25
        • 2015-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多