开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
大规模的 JavaScript : 单一的服务层 - 技术翻译 - 开源中国社区

大规模的 JavaScript : 单一的服务层 【已翻译100%】

oschina 推荐于 5年前 (共 8 段, 翻译完成于 12-17) 评论 12
收藏  
78
推荐标签: Backbone.js 待读

当我开始为YouNow设计最初的JS应用程序时,我追求的是建立一种可以被我们的Backbone.js应用和一次性脚本/项目同时使用的架构。随着时间的推移这些架构增长相当迅速,现在他们都成块铁板一样,固定在那很稳定。在本文中,我将讨论一个后端API服务层的设计动机,它的优点和缺点,并提出一些替代性建议,相当于头脑风暴。

后端API服务层

尽管你可能已经实现了你的后端API(用MVC或其他方式),想记住和重新实现API服务接口的细节是一件非常繁琐的事情。当项目里队友说,他们正在开发的功能是需要登录的时候,他们需要推倒重来吗?或者你可以给他们一个之前开发好的JS函数供他们调用?

devilteam2006
 翻译得不错哦!

我想开发一个JS客户端来解决这些问题,并把它命名为younow.js,它将允许任何JS应用程序来与我们的后端进行方便的交互。有一个需要登录的新增功能?不用担心!只需调用YouNow.Api.login()并绑定相应的回调方法就可以了。在该例子中,服务层公开了一个在YouNow.Api命名空间中的登录功能。

YouNow.Api.login()
  .done(function (loginData) {
    // Do what you need with the login data
  })
  .fail(function (errorMsg) {
    // Handle the error as you wish
  });
注:对于这个JS服务层端点的实现, 如果你不喜欢jQuery那样的绑定风格的话,你可以按约定的方式,绑定自己的成功/失败回调方法到这些端点上。我个人倒是很喜欢JQUERY这种风格的链接/管道特性和标准接口模式。
devilteam2006
 翻译得不错哦!

听起来不错,不是吗?

优点:对于每一个YouNow.Api命名空间内的结点,服务层younow.js将会有一个关于预期参数和被隐藏的复杂机制的文档说明。尤其是使用服务的用户不用去担心这个请求是GET还是POST,是通过CDN返回还是我们直接发送的,更不用担心怎样去构建URL和如何处理jsonp数据。对于一个单点来说,所有的后台交互都是孤立的。

缺点:这个文件的增长迅速,几乎超出你的想象。对于每一次后台调用,我们需要一个增加新的YouNow.Api的结点。你可以抽象业务到helper函数中来处理响应,jsonp,cdn地址和$.ajax调用。然而,对于一个应用来说,这个文件已经达到40kb了。每一个应用有自己的API结点集,每一个都和younow.js交互。这对于维护来说是非常困难的。

tnjin
 翻译得不错哦!

现在想象一下,一个简单的小应用程序,如媒体播放器( 例如一个JS的包装器,JWPlayer的初始器)。它可能需要一个或两个接口(登录的接口和 检索广播信息的接口)。那么它必须下载整个40KB的数据包。

另一种实现1:为每个应用程序分配一个服务层

常规的服务层可以是简单的辅助函数的关键集合 (ajax,CDN,约定)每一个应用程序在加载自身的服务层函数将继承YouNow.Api命名空间。

好处:这解决了主服务层不断膨胀的问题。
好处:坚持什么时候以及如何扩展一个应用程序的命名空间的原则,该解决方案可以清晰地扩展出多种应用程序。
缺点:每一个应用程序的个性化服务层可能变得非常臃肿。
缺点:如果两个应用程序都对同一个端点接口有共同的需求时,怎么办?

devilteam2006
 翻译得不错哦!

另一种实现2:封装结点

登陆功能能够封装成一个登陆服务,这样应用就可以嵌入或者直接使用了:

// loginservice.js
YouNow.Mixins.LoginService = {
  login: function () {},
  logout: function () {}
};
 
// broadcastservice.js
YouNow.Mixins.BroadcastService = {
  get: function () {},
  delete: function () {}
};
优点:服务层变成了一些了经过封装的结点。数量的增长将会体现在两个方面:封装的数量和函数的数量。单层结构只会在一个方面增长,所以这个方案有更好的伸缩性。

我现在正在想弥补这个方案的缺点,这也成为第三种最好的实现方式,但是我十分喜欢这种方式;通过下面的第三种实现方式,它修复了模块的过度膨胀问题。

如果你发现这个方法的巨大缺陷,请给我留言。

tnjin
 翻译得不错哦!

另一种实现3:完全脱离服务层。将交互转移到模块内完成

因为服务层的存在,想要和后台进行交互的Backbone模块只需要简单的调用YouNow.Api离得函数就行。现在这些模块的实现是精简的,但是你也能够理解这些模块其实不必传输自己的数据到别的地方。感觉就像是模块应该拥有那种功能。

完全脱离服务层,我们将会有一个拥有登陆/登出功能的用户模块和完全实现(或许是基于基本模块的扩展,这样我们能够脱离CDN和ajax helper)。

优点:各模块拥有适当的功能。

tnjin
 翻译得不错哦!

缺点:随着时间推移,越来越多的函数充斥着这个模块。不是很确定这是否是一个缺点,因为对于“胖模型”来说,这也许就是一个优点。

【更新】缺点:如果小的应用想要实例化你的模块现在需要Backbone(或者其他你在使用的框架)和它的依赖模块,很不幸,将会为模块的臃肿付出点代价,但是这可以作为你的系统统一化的一个折中方案。

任何想要使用登陆/登出功能的应用都必须要实例化一个用户模块。这并不令人讨厌。举个例子,多媒体播放器应用需要登陆一个用户。那么现在有一个你的用户,是一个用户模块的实例。现在就可以调用它的登陆功能了。与之相比,不用去直接调用YouNow.Api.login()。

tnjin
 翻译得不错哦!

通过上面的第二种实现方式(封装方式),用户模块将不会拥有登录/登出功能。反而,它将会封装登录服务,也许使用Cocktail.js——我也是这个项目的维护者之一;)。

这可以间接的访问。我的意思是,你查看用户模块的定义,找不到登录/登出方法。那么如何一眼看出用户模块有那中功能呢?从技术上说,我们传递数据到另一个服务,登录服务获得在封装好的用户模块的数据,这样就实现了用户模块自己的登录功能。

什么是最好的解决方案?

我认为解决方案其实就是实现方式2和3的混合体。

在目前,服务层是一个好的想法,但是不能满足复杂应用的伸缩性。目前,我已经迁移到胖模块的实现(第三种方式),但是还没搭配使用分组封装(第二种方式)。

或许还有别的实现思路?

tnjin
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(12)
Ctrl/CMD+Enter

学习~
不明白
翻译都不通顺
TMD,到哪儿也搞成三层,烦不烦。
我是来看评论的
作者提到的问题其实不仅仅是js的问题,任何语言都存在。api的设计似乎不存在最优模式,还存在一个使用习惯的问题。你封装的越密,重用性就越差,你松了,那么灵活性就提高,易用性就降低。个人觉得比较合理的做法是分层式,就是说最底层是小的api,在这小api的基础上构建更高层次的服务,这个层不必限于2层。就像你提到的第三种方法应该建立在第2种或者第一种的基础上,这样不同的用户可以选择使用不同层次的api。
Backbone是什么语言?
我可以断定:作者不太了解JS。
基本的思想都没有还谈什么软体设计。
不明白作者想说啥
既然已经是大规模的javascript. 还考虑什么40K.
现在人就想把什么都做成通用的.
最近也在思考这个问题,采用什么样的方案,需要看是什么样的系统,个人偏向于第2个方案,对于复用比较多的api,搞个comm的文件,统一调用下
顶部