代码之家  ›  专栏  ›  技术社区  ›  Anurag

设计一个流畅的javascript接口来抽象ajax的异步特性

  •  19
  • Anurag  · 技术社区  · 15 年前

    我应该如何设计一个api来隐藏ajax和http请求的异步特性,或者延迟它来提供一个流畅的接口。展示twitter的新示例 Anywhere 应用程序编程接口:

    // get @ded's first 20 statuses, filter only the tweets that
    // mention photography, and render each into an HTML element
    T.User.find('ded').timeline().first(20).filter(filterer).each(function(status) {
        $('div#tweets').append('<p>' + status.text + '</p>');
    });
    
    function filterer(status) {
        return status.text.match(/photography/);
    }
    

    vs this(每个调用的异步特性都清晰可见)

    T.User.find('ded', function(user) {
        user.timeline(function(statuses) {
            statuses.first(20).filter(filterer).each(function(status) {
                $('div#tweets').append('<p>' + status.text + '</p>');
            });
        });
    });
    
    function filterer(status) {
        return status.text.match(/photography/);
    }
    

    它找到用户,获取他们的tweet时间线,只过滤前20条tweet,应用自定义过滤器,并最终使用回调函数处理每个tweet。

    我猜这样一个设计良好的api应该像一个查询生成器(think orms)一样工作,在这里每个函数调用都会生成查询(在本例中是http url),直到它碰到一个循环函数(如each/map/etc),http调用才会进行,传入的函数就会成为回调函数。

    一个简单的开发路线是使每个ajax调用同步,但这可能不是最好的解决方案。我有兴趣找出一种使它异步的方法,并且仍然隐藏ajax的异步特性。

    3 回复  |  直到 15 年前
        1
  •  20
  •   Christian C. Salvadó    15 年前

    看看几天前Twitter工程师Dustin Diaz在@Anywhere上发表的以下文章:

    他谈到了一种非常好的技术,它允许您在异步方法上实现一个流畅的接口,基本上是独立于回调而链接在一起的方法,使用一个非常简单的队列实现。

        2
  •  5
  •   coolaj86    14 年前

    我在发展 FutureJS 最初是基于 Crockford's promises ( original slides )当前的目标是成为javascript的异步工具箱并消除链接混乱。

    futures.chainify(提供者、消费者、上下文、参数)

    异步方法队列允许您对可能可用或不可用的数据链接操作。 这就是Twitter的@Anywhere API的工作原理。

    您可能需要一个以这种方式远程获取数据的模型:

    Contacts.all(params).randomize().limit(10).display();
    Contacts.one(id, params).display();
    

    可以这样实施:

    var Contacts = Futures.chainify({
      // Providers must be promisables
      all: function(params) {
        var p = Futures.promise();
        $.ajaxSetup({ error: p.smash });
        $.getJSON('http://graph.facebook.com/me/friends', params, p.fulfill);
        $.ajaxSetup({ error: undefined });
        return p.passable();
      },
      one: function(id, params) {
        var p = Futures.promise();
        $.ajaxSetup({ error: p.smash });
        $.getJSON('http://graph.facebook.com/' + id, params, p.fulfill);
        $.ajaxSetup({ error: undefined });
        return p.passable();
      }
    },{
      // Consumers will be called in synchronous order
      // with the `lastResult` of the previous provider or consumer.
      // They should return either lastResult or a promise
      randomize: function(data, params) {
        data.sort(function(){ return Math.round(Math.random())-0.5); // Underscore.js
        return Futures.promise(data); // Promise rename to `immediate`
      },
      limit: function(data, n, params) {
        data = data.first(n);
        return Futures.promise(data);
      },
      display: function(data, params) {
        $('#friend-area').render(directive, data); // jQuery+PURE
        // always return the data, even if you don't modify it!
        // otherwise your results could be unexpected
        return data;
      }
    });
    

    需要知道的事情:

    • providers -返回数据的promisables
    • consumers -使用和/或更改数据的函数
      • 第一个参数必须是 data
      • 当返回一个promisable时,链中的下一个方法将不执行,直到实现了承诺
      • 当返回“literal object”时,链中的下一个方法将使用该对象
      • 回来的时候 undefined (或不返回任何内容)链中的下一个方法将使用定义的对象
    • context - apply() 向每个提供者和消费者发送,从而成为 this 对象
    • params -保留以备将来使用

    或者,您可以使用同步回调链接-您可能在别处看到的是chain()。next()或then():

    Futures.sequence(function(callback) {
    
        $.getJSON("http://example.com", {}, callback);
    
    }).then(function(callback, result, i, arr) {
    
        var data = transform_result(result);
        $.getJSON("http://example.com", data, callback);
    
    }).then(...)
    

    我给它起了名字 sequence 而不是 chain 因为js已经有一个名为 我还想为我的库使用methodname。

    Take a peek let me know what you think .

    futuresjs将与jquery、dojo等一起工作,没有问题。没有依赖关系。它将使用node.js(使用env.js时使用rhino)。

    =8

    关于orm/mvc的修复,请注意 JavaScriptMVC SproutCore . 我也在研究我自己的解决方案triforcejs,但我还没有准备好发布任何东西。

    P.P.S.示例 promisables

    var doStuff = function (httpResult) {
        // do stuff
      },
      doMoreStuff = function (httpResult) {
        // do more stuff
      };
    
    function fetchRemoteData(params) {
      var promise = Futures.promise();
      $.getJSON("www.example.com", params, promise.fulfill, 'jsonp');
      return promise;
    }
    
    p = fetchRemoteData(params);
    p.when(doStuff);
    p.when(doMoreStuff);
    
        3
  •  0
  •   John K    15 年前

    我相信,ajax同步问题已经被jquery(即 ajax call 它允许您通过 异步的 财产)。如果选择同步模式,则隐藏实现的异步性质。

    jquery也是一个流畅的接口和链接的例子。还有其他的库也这样做。省得你重新发明轮子-让你马上滚动你正在寻找的。

    如果这可以作为一个答案,那么您可以在这些功能之间获得一些良好的自动浏览器兼容性。这些东西需要很长时间才能从头开始。

    我看到Twitter的新Anywhere API注意到jquery——如果你仔细研究一下,也许一切都已经存在了。