我将如何设计一个 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/);
}
与此(每个调用的异步性质是清晰可见)
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/等,进行 HTTP 调用,传入的函数将成为回调。
一个简单的开发路线是使每个 AJAX 调用同步,但这可能不是最好的解决方案。我有兴趣找出一种使其异步的方法,并且仍然隐藏 AJAX 的异步本质。
How would I design an API to hide the asynchronous nature of AJAX and HTTP requests, or basically delay it to provide a fluent interface. To show an example from Twitter's new 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 (asynchronous nature of each call is clearly visible)
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/);
}
It finds the user, gets their tweet timeline, filters only the first 20 tweets, applies a custom filter, and ultimately uses the callback function to process each tweet.
I am guessing that a well designed API like this should work like a query builder (think ORMs) where each function call builds the query (HTTP URL in this case), until it hits a looping function such as each/map/etc., the HTTP call is made and the passed in function becomes the callback.
An easy development route would be to make each AJAX call synchronous, but that's probably not the best solution. I am interested in figuring out a way to make it asynchronous, and still hide the asynchronous nature of AJAX.
发布评论
评论(3)
我相信,AJAX 同步问题已经被 jQuery 等库抽象出来了(即它的 ajax 调用 允许您通过 async 属性指定异步或同步操作)。如果选择同步模式,则会隐藏实现的异步性质。
jQuery 也是流畅界面和链接的一个例子。还有其他库也做同样的事情。避免您重新发明轮子 - 让您立即找到您想要的东西。
如果这可以作为答案,那么您将在这些功能之间获得良好的自动浏览器兼容性。这些东西需要很长时间才能从头开始构建。
我看到 Twitter 的新 Anywhere API 注释 jQuery - 如果您进行一些挖掘,也许一切都已经在那里。
The AJAX synchronous issue, I believe, has already been abstracted away by libraries such as jQuery (i.e. its ajax call which allows you to specify async or synch operation through the async property). The synchronous mode, if chosen, hides the asynchronous nature of the implementation.
jQuery is also an example of a fluent interface and chaining. There are other libraries that do the same. Saves you reinventing the wheel - gets you rolling right away with what you are looking for.
If this works as an answer then you get some good automatic browser compatibility across these features. That stuff takes a long while to build out from scratch.
I see Twitter's new Anywhere API notes jQuery - maybe everything is already there if you do some digging.
我正在开发 FutureJS ,它最初基于 Crockford 的承诺 (原始幻灯片)。当前的目标是成为 JavaScript 的异步工具箱并消除链式混乱。
Futures.chainify(providers, Consumers, context, params)
异步方法排队允许您对可能可用或不可用的数据进行链接操作。
这就是 Twitter 的 @Anywhere api 的工作原理。
您可能需要一个以这种方式远程获取数据的模型:
可以像这样实现:
要知道的事情:
providers
- 返回数据的 promisablesconsumers
- 使用和的函数或更改数据数据
未定义
(或不返回任何内容)时,链中的下一个方法将使用已定义的对象context
-apply()
d 来每个提供者和消费者,从而成为this
对象params
- 保留供将来使用或者,您可以使用同步回调链接 - 您可能在其他地方看到过 chain().next () 或 then():
我将其命名为
sequence
而不是chain
因为 _.js 已经有一个名为chain
的方法,我想也为我的库使用 _.methodName 。看一看和让我知道您的想法。
FuturesJS 可以毫无问题地与 jQuery、Dojo 等一起工作。没有依赖性。它将与 Node.js 一起使用(当使用 env.js 时,还可以与 Rhino 一起使用)。
=8^
D至于 ORM / MVC 修复 - 您可以查看 JavaScriptMVC 和 SproutCore。我也在开发自己的解决方案 TriforceJS,但我还没有准备好发布任何内容。
PPS
promisables
示例I'm developing FutureJS which was originally based on Crockford's promises (original slides). The current goal is to be the Async Toolbox of JavaScript and eliminate chaining clutter.
Futures.chainify(providers, consumers, context, params)
Asynchronous method queueing allows you to chain actions on data which may or may not be readily available.
This is how Twitter's @Anywhere api works.
You might want a model which remotely fetches data in this fashion:
Which could be implemented like so:
Things to know:
providers
- promisables which return dataconsumers
- functions which use and or change datadata
undefined
(or not returning anything) the next method in the chain will use the defined objectcontext
-apply()
d to each provider and consumer, thus becoming thethis
objectparams
- reserved for future useAlternatively you could use synchronous callback chaining - what you may have seen elsewhere as chain().next() or then():
I named it
sequence
rather thanchain
since _.js already has a method namedchain
and I'd like to use _.methodName for my library as well.Take a peek and let me know what you think.
FuturesJS will work alongside jQuery, Dojo, etc without issue. There are no dependencies. It will work with Node.js (and Rhino when using env.js).
=8^D
P.S. As to the ORM / MVC fix - you can check out JavaScriptMVC and SproutCore. I'm also working on my own solution called TriforceJS, but I don't have anything ready for release yet.
P.P.S Example of
promisables
请查看 Twitter 工程师 Dustin Diaz 几天前在 @anywhere 上发表的以下文章:
他谈到了一种非常好的技术,该技术允许您使用非常简单的队列实现,在异步方法上实现流畅的接口,基本上是独立于回调的方法链接在一起。
Give a look to the following article published just a couple of days ago by Dustin Diaz, Twitter Engineer on @anywhere:
He talks about a really nice technique that allows you to implement a fluent interface on asynchronous methods, basically methods chained together independent of a callback, using a really simple Queue implementation.