19

我将如何设计一个 API 来隐藏 AJAX 和 HTTP 请求的异步性质,或者基本上延迟它以提供流畅的接口。举一个 Twitter 新的Anywhere API 的例子:

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

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

我猜测像这样设计良好的 API 应该像查询构建器(想想 ORM)一样工作,其中每个函数调用都构建查询(在这种情况下为 HTTP URL),直到它遇到诸如 each/map/etc 之类的循环函数,进行 HTTP 调用,传入的函数成为回调。

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

4

3 回答 3

20

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

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

于 2010-05-09T02:24:33.780 回答
5

我正在开发FutureJS,它最初基于Crockford 的承诺原始幻灯片)。当前的目标是成为 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
    • 当返回一个承诺时,链中的下一个方法将不会执行,直到承诺被履行
    • 当返回一个“文字对象”时,链中的下一个方法将使用该对象
    • 当返回undefined(或不返回任何东西)时,链中的下一个方法将使用定义的对象
  • context-d 对每个提供者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 已经有一个命名的方法chain,我也想为我的库使用 _.methodName 。

看看让我知道你的想法

FuturesJS 将毫无问题地与 jQuery、Dojo 等一起工作。没有依赖关系。它适用于 Node.js(以及使用 env.js 时的 Rhino)。

=8^D

PS 至于 ORM / MVC 修复 - 您可以查看JavaScriptMVCSproutCore。我也在研究我自己的名为 TriforceJS 的解决方案,但我还没有准备好发布任何东西。

PPS 示例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);
于 2010-07-14T23:05:03.987 回答
0

我相信 AJAX 同步问题已经被 jQuery 等库抽象出来(即它的ajax 调用,它允许您通过async属性指定异步或同步操作)。同步模式(如果选择)隐藏了实现的异步特性。

jQuery 也是一个流畅的接口和链接的例子。还有其他库也这样做。节省您重新发明轮子 - 让您立即使用您正在寻找的东西。

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

我看到 Twitter 的新 Anywhere API 注释 jQuery - 如果您进行一些挖掘,也许一切都已经存在。

于 2010-05-09T02:42:57.857 回答