收藏本站腾讯微博新浪微博

经典论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

蓝色理想 最新研发动态 网站开通淘帖功能 - 蓝色理想插件 论坛内容导读一页看论坛 - 给官方提建议

论坛活动及任务 地图和邮件任务 请多用悬赏提问 热夏来袭,选一款蓝色理想的个性T恤吧!

手机上论坛,使用APP获得更好体验 急需前端攻城狮,获得内部推荐机会 论坛开通淘帖功能,收藏终于可以分类了!

搜索
查看: 3943|回复: 17

[技术相关] 聊聊JS的开发

[复制链接]
发表于 2013-3-21 20:50:43 | 显示全部楼层 |阅读模式

如果只是写一些简单的脚本,例如tab组件、幻灯片效果、瀑布流这些代码行数不多的JS应用,其实是一件非常简单的事情。

但是当自己的代码库越来越长后,特别是经常有重用的需求的时候,就会觉得如何组织代码文件是一件比较费考量的事情。

如果都写在一个文件里,那么开发和维护就会非常头痛,要在上下几千、上万行里找某些特定的代码进行参考或修改简直能把人逼疯。。。有时候仅仅想要使用其中的很小一部分功能,却要加载整个的库,对俺这种人来说也是很不爽的事情(虽然整个JS文件也不一定比一个图片大)

如果拆开成为若干文件,那么文件之间的相互依赖性,或者说加载的先后顺序控制也是一个麻烦事。此外,在Web页面中,引用太多的脚本文件,一是会增加很多的连接开销,二是对于网络慢的访问者来说很容易卡住。


貌似比较好的做法是开发的时候,把JS库拆开为若干文件,每个文件中说明依赖性。实际使用的时候,用一定的工具把源文件编译为一个单独的JS文件来引用。


俺比较孤陋寡闻,关于JS开发和文件、版本管理有没有什么比较成熟的解决软件或方案?有经验的童鞋来分享一下呗。。。

本帖被以下淘专辑推荐:

  • · 进阶|主题: 19, 订阅: 1
  • · 经验|主题: 4, 订阅: 0
发表于 2013-3-21 21:28:37 | 显示全部楼层
COMMONJS  

AMD阵营的requirejs
CMD阵营的sea.js

纯加载器的lab.js

或者 以老大你的水平 写的更好的
回复 支持 反对

使用道具 举报

发表于 2013-3-21 21:31:27 | 显示全部楼层
er 补充下 上线打包的方案 sea.js据说用的grunt

我的解决方案是服务端动态合并 网站是这个 www.meilishuo.com 可以从网络看请求是合并的  非AD啊 勿T
回复 支持 反对

使用道具 举报

发表于 2013-3-23 13:14:17 | 显示全部楼层
终于见到二哥的身影了....


我是来膜拜的
回复 支持 反对

使用道具 举报

发表于 2013-3-25 11:14:41 | 显示全部楼层
JS能力不强,不过也经常碰到这问题。
现在是一个项目组成一个专门的库,这样不用调用很多用不到的东西,也不会感觉很乱。
大项目就分成公共库和单独的功能性JS,只有偶尔几个页面需要的东西单独加载功能性JS。
不过修改起来还是挺麻烦的。。。。各种替换。。。
回复 支持 反对

使用道具 举报

发表于 2013-3-25 11:44:54 | 显示全部楼层
什么时候给我们后生补一下知识
回复 支持 反对

使用道具 举报

发表于 2013-3-25 13:07:42 | 显示全部楼层
我开始讨厌seajs了。还是比较喜欢以前的公私分法处理。
回复 支持 反对

使用道具 举报

发表于 2013-3-25 15:16:39 | 显示全部楼层
Enoch 发表于 2013-3-21 21:28
COMMONJS  

AMD阵营的requirejs

我来顶requirejs,习惯先加载再使用
而且页头声明,查看依赖方便
回复 支持 反对

使用道具 举报

发表于 2013-3-26 01:39:36 | 显示全部楼层
本帖最后由 Missx 于 2013-3-26 02:04 编辑

介绍库之前首先要介绍下标准和使用方法的差异。
AMD:
  1. define(["module-1","module-2"],function(module1,module2){
  2. ... do something.
  3. })
复制代码
CMD:

  1. define(function(require,export,module){
  2.   var module1 = require("module-1");
  3.   var module2 = require("module-2");
  4. });
复制代码
如果以AMD的标准,在使用的时候无需在function内部再去解析require,避免了一个解析过程,同时如果在函数内部再次定义,声明引用的数组里面是可以使用变量调用的。缺点是如果依赖太多,前面会很长。

如果以CMD的标准,使用的时候先要将整体的function toString 再去正则匹配require("xxx")的内容。这个时候强制要求xxx必须为一个固定的字符串。同时require不能重命名。

两者各有千秋,现阶段AMD主要在web前端这块,CMD则是在后端。

另外在AMD上派生出来一个LMD,增加了lazy load的特性。

目前实现Module加载的库有很多:

oz.js : dexteryy 豆瓣的,介绍上是说是微内核,实际上看介绍图也的确是衍生出一堆足够用的内容 http://ozjs.org/cn/,推广少,关注度不高。

sea.js: 玉伯的,推广程度比上面的高,大概是 oz.js:sea.js = 1:10000的样子,使用的时候在早期是坚持Common.js的api,后期是否有转变没关注过。http://seajs.org/docs/,附带有优化脚本。可以帮忙做压缩合并啥的。

require.js, 国际范围内知名度最高的一个,也是因为它才有了AMD和CMD标准的差别。事实上当前的requirejs可以使用两种标准来定义模块(当然也增加了额外的性能开支)。有r.js 做优化脚本,会帮你做一些模块命名合并之类的工作。缺点是纯英文文档。http://requirejs.org/,另外作者开了一个坑,做了一个简化版的requirejs: alameda,里面用到了一些新的js特性,也摒弃了一些不常用的API。

LMD: 就是AMD派生出来的一个库,主要特性就是延迟加载。关注了下,但是没具体谁用过。https://github.com/azproduction/lmd

browserify: CMD标准,但是作为前端管理库感觉又太重了。主要的优点就是nodejs的module可以直接拿来用。完全无缝衔接前后端。但是好像需要编译一次。

前端这块应该还有其他的库,但是我个人没怎么关注过。

另外如果想要了解如何编写一个js module,这里有一篇很好的文章(当然也是英文的):

http://addyosmani.com/writing-modular-js/

当中介绍了AMD CMD 实际编写module的过程以及优缺点,还介绍了ES Harmony 标准下module的特性(算是未来篇)。

PS.个人在项目里面用的是requirejs,国人维护的项目始终还是担心是个坑。
回复 支持 反对

使用道具 举报

发表于 2013-3-26 02:02:22 | 显示全部楼层
本帖最后由 Missx 于 2013-3-26 09:44 编辑

以上是module的加载器,或者说是在实际运行的时候的依赖管理,另外还有js 的包管理,也就是编码过程当中的包管理,协助你从远程下载包依赖的其他库。

js的包管理目前的的解决方案都类似,都是走的node环境。我知道的有两个:

twitter 的 bower  http://twitter.github.com/bower/

visionmedia 的 component https://github.com/component/component

前者的知名度很高,Google维护的前端开发的整体解决方案 yeoman 就是用它做依赖管理的。

后者的开发者是开发过expressjs / jade /mocha的人

我没有用过,但是个人推荐是使用yeoman(bower)。无他,就是大公司的,放心。component  的优势在于目前的环境还可以。能使用组件比较多。

当然,bower 之前有测试过,在使用的时候它把整个源码都download下来,感觉现在离实用还有点距离。如果需要实用,建议直接把bower的源码fix下再用。

如果只是简单的混合依赖文件,也可以通过grunt+解析包信息文件package.json 来做到。
回复 支持 反对

使用道具 举报

发表于 2013-12-24 19:54:49 | 显示全部楼层
xmlovedoudou 发表于 2013-3-25 13:07
我开始讨厌seajs了。还是比较喜欢以前的公私分法处理。

公私分法是什么?求细节
为何讨厌seajs
回复 支持 反对

使用道具 举报

发表于 2013-12-24 20:32:35 | 显示全部楼层
楼上最近坟挖的倒爽。。

这个是最符合主题要求的东西
https://github.com/alibaba/nginx-http-concat
回复 支持 反对

使用道具 举报

发表于 2013-12-24 20:52:29 | 显示全部楼层
kran 发表于 2013-12-24 20:32
楼上最近坟挖的倒爽。。

这个是最符合主题要求的东西

其实不是哈。

这一个只是一个nginx的标准模块,用于编译、合并文本静态资源的。

@hutia 提到的分两个问题:

1. 开发阶段:静态资源的组织与划分;
2. 线上环境:资源的编译与合并;
回复 支持 反对

使用道具 举报

发表于 2013-12-24 22:26:03 | 显示全部楼层
Evance 发表于 2013-12-24 20:52
其实不是哈。

这一个只是一个nginx的标准模块,用于编译、合并文本静态资源的。

。。。前端真是越来越复杂了,从我们这边前端的项目看,文件组织一般脱不开按功能和按角色来划分,实在不行就参考后端。
上线时到底哪些合一起哪些不合一起或者都不合按需加载才是问题,我觉得concat模块的动态合并能解决好大一部分问题。
工具的话,grunt能大包大揽的了,实在不想学用make都可以。。。

ps:以上是一个后端不负责任的话
回复 支持 反对

使用道具 举报

发表于 2013-12-30 18:44:51 | 显示全部楼层
本帖最后由 Missx 于 2013-12-30 19:03 编辑
kran 发表于 2013-12-24 22:26
。。。前端真是越来越复杂了,从我们这边前端的项目看,文件组织一般脱不开按功能和按角色来划分,实在不 ...


遇到快300个js文件管理的时候按需加载就是挑战了。
另外你这种动态合并不适合node-webkit以及chrome packaged app 形式的webapp管理

例子:
https://github.com/adobe/brackets/blob/master/src/brackets.js
依赖代码:
  1.    "use strict";
  2.    
  3.     // Load dependent non-module scripts
  4.     require("widgets/bootstrap-dropdown");
  5.     require("widgets/bootstrap-modal");
  6.     require("widgets/bootstrap-twipsy-mod");
  7.     require("thirdparty/path-utils/path-utils.min");
  8.     require("thirdparty/smart-auto-complete-local/jquery.smart_autocomplete");
  9.    
  10.     // Load dependent modules
  11.     var Global                  = require("utils/Global"),
  12.         AppInit                 = require("utils/AppInit"),
  13.         LanguageManager         = require("language/LanguageManager"),
  14.         ProjectManager          = require("project/ProjectManager"),
  15.         DocumentManager         = require("document/DocumentManager"),
  16.         EditorManager           = require("editor/EditorManager"),
  17.         CSSInlineEditor         = require("editor/CSSInlineEditor"),
  18.         JSUtils                 = require("language/JSUtils"),
  19.         WorkingSetView          = require("project/WorkingSetView"),
  20.         WorkingSetSort          = require("project/WorkingSetSort"),
  21.         DocumentCommandHandlers = require("document/DocumentCommandHandlers"),
  22.         FileViewController      = require("project/FileViewController"),
  23.         FileSyncManager         = require("project/FileSyncManager"),
  24.         KeyBindingManager       = require("command/KeyBindingManager"),
  25.         Commands                = require("command/Commands"),
  26.         CommandManager          = require("command/CommandManager"),
  27.         CodeHintManager         = require("editor/CodeHintManager"),
  28.         PerfUtils               = require("utils/PerfUtils"),
  29.         FileSystem              = require("filesystem/FileSystem"),
  30.         QuickOpen               = require("search/QuickOpen"),
  31.         Menus                   = require("command/Menus"),
  32.         FileUtils               = require("file/FileUtils"),
  33.         MainViewHTML            = require("text!htmlContent/main-view.html"),
  34.         Strings                 = require("strings"),
  35.         Dialogs                 = require("widgets/Dialogs"),
  36.         DefaultDialogs          = require("widgets/DefaultDialogs"),
  37.         ExtensionLoader         = require("utils/ExtensionLoader"),
  38.         SidebarView             = require("project/SidebarView"),
  39.         Async                   = require("utils/Async"),
  40.         UpdateNotification      = require("utils/UpdateNotification"),
  41.         UrlParams               = require("utils/UrlParams").UrlParams,
  42.         PreferencesManager      = require("preferences/PreferencesManager"),
  43.         Resizer                 = require("utils/Resizer"),
  44.         LiveDevelopmentMain     = require("LiveDevelopment/main"),
  45.         NodeConnection          = require("utils/NodeConnection"),
  46.         NodeDomain              = require("utils/NodeDomain"),
  47.         ExtensionUtils          = require("utils/ExtensionUtils"),
  48.         DragAndDrop             = require("utils/DragAndDrop"),
  49.         ColorUtils              = require("utils/ColorUtils"),
  50.         CodeInspection          = require("language/CodeInspection"),
  51.         NativeApp               = require("utils/NativeApp"),
  52.         _                       = require("thirdparty/lodash");
  53.         
  54.     // Load modules that self-register and just need to get included in the main project
  55.     require("command/DefaultMenus");
  56.     require("document/ChangedDocumentTracker");
  57.     require("editor/EditorStatusBar");
  58.     require("editor/EditorCommandHandlers");
  59.     require("editor/EditorOptionHandlers");
  60.     require("view/ViewCommandHandlers");
  61.     require("help/HelpCommandHandlers");
  62.     require("search/FindInFiles");
  63.     require("search/FindReplace");
  64.     require("extensibility/InstallExtensionDialog");
  65.     require("extensibility/ExtensionManagerDialog");
  66.     require("editor/ImageViewer");
  67.    
  68.     // Compatibility shims for filesystem API migration
  69.     require("project/FileIndexManager");
  70.     require("file/NativeFileSystem");
  71.     require("file/NativeFileError");
复制代码
回复 支持 反对

使用道具 举报

发表于 2013-12-30 23:11:06 | 显示全部楼层
Missx 发表于 2013-12-30 18:44
遇到快300个js文件管理的时候按需加载就是挑战了。
另外你这种动态合并不适合node-webkit以及chrome p ...

像这种复杂的依赖现在有什么好的做法吗?
回复 支持 反对

使用道具 举报

发表于 2013-12-31 09:48:33 | 显示全部楼层
本帖最后由 Missx 于 2013-12-31 09:51 编辑
kran 发表于 2013-12-30 23:11
像这种复杂的依赖现在有什么好的做法吗?


就是上面提到那些 requirejs(目前brackets 使用到的解决方案),seajs,主要是让web页面级别的前端也能用类似nodejs的开发方式来进行开发,方便管理依赖和文件组织。

在代码层面其实这个和后端的C类似,自己模块需要的依赖在开头声明一下,使用的时候就可以假定已经加载了,主要的声明方法和加载顺序由库做掉,使得前端主要专注在自己代码上即可。这种模式下只要注意异步和避免循环依赖即可。
回复 支持 反对

使用道具 举报

发表于 2013-12-31 20:35:40 | 显示全部楼层
Missx 发表于 2013-12-31 09:48
就是上面提到那些 requirejs(目前brackets 使用到的解决方案),seajs,主要是让web页面级别的前端也 ...

看来每种语言都只能这样了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|Archiver|手机版|blueidea.com ( 湘ICP备12001430号 )  

GMT+8, 2020-4-3 15:36 , Processed in 0.112020 second(s), 8 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表