破晓 发表于 2016-8-17 17:21:01

再谈 SeaJS 与 RequireJS 的差异

来源:http://div.io/topic/430<div><br></div><div><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">“历史不是过去,历史正在上演。随着 W3C 等规范、以及浏览器的飞速发展,前端的模块化开发会逐步成为基础设施。一切终究都会成为历史,未来会更好。”——引用玉伯<a href="https://github.com/seajs/seajs/issues/588" target="_blank" style="text-decoration: none; color: rgb(49, 135, 219);">原文</a>最后一段话,我个人也非常赞同。既然谈到了“未来”,我个人认为:前端 js 模块如果继续发展,其模块格式很可能会成为未来 WEB 一种标准规范,产生多种实现方式。就好比 JSON 格式一样,最终成为标准、被浏览器原生实现。</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">谁更有能成为未来的异步模块标准?SeaJS 遵循 CMD 规范,RequireJS 遵循 AMD 规范,先从这两种不同的格式说起。</p><h2 style="font-size: 26px; margin-top: 20px; margin-bottom: 20px; counter-reset: section 0; font-weight: normal; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif;">CMD</h2><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><strong>CMD 模块依赖声明方式:</strong></p><pre style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; border: 1px solid rgb(221, 221, 221); font-size: 12px; line-height: 18px; overflow: auto; padding: 6px 10px; border-radius: 3px; word-break: break-all; color: rgb(51, 51, 51); background-color: rgb(248, 248, 248);"><code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: 1.5; border: 0px none; border-radius: 0px; font-size: inherit; background: none;">define(function (require) {
    var a = require('./a');
    var b = require('./b');
    // more code ..
})
</code></pre><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">CMD 依赖是就近声明,通过内部<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">require</code>方法进行声明。但是因为是异步模块,加载器需要提前加载这些模块,所以模块真正使用前需要提取模块里面所有的依赖。无论是加载器即时提取,还是通过自动化工具预先提取,CMD 的这种依赖声明格式只能通过静态分析方式实现,这也正是 CMD 的弊端所在。</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><strong>CMD 规范的弊端</strong></p><ol style="padding-left: 30px; margin-bottom: 14px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><li>不能直接压缩:<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">require</code>是局部变量,意味着不能直接的通过压缩工具进行压缩,若<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">require</code>这个变量被替换,加载器与自动化工具将无法获取模块的依赖。</li><li>模块书写有额外约定:路径参数不能进行字符串运算,不能使用变量代替,否则加载器与自动化工具无法正确提取路径。</li></ol><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">规范之外的约定意味着更多的文档说明,除非它们也是规范中的一部分。</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">注:SeaJS 静态分析实现是把模块包<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">toString()</code>后使用正则提取<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">require</code>部分得到依赖的模块路径。</p><h2 style="font-size: 26px; margin-top: 20px; margin-bottom: 20px; counter-reset: section 0; font-weight: normal; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif;">AMD</h2><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><strong>AMD 模块依赖声明方式:</strong></p><pre style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; border: 1px solid rgb(221, 221, 221); font-size: 12px; line-height: 18px; overflow: auto; padding: 6px 10px; border-radius: 3px; word-break: break-all; color: rgb(51, 51, 51); background-color: rgb(248, 248, 248);"><code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: 1.5; border: 0px none; border-radius: 0px; font-size: inherit; background: none;">define(['./a', './b'], function (a, b) {
    // more code ..
})
</code></pre><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">AMD 的依赖是提前声明。这种优势的好处就是依赖无需通过静态分析,无论是加载器还是自动化工具都可以很直接的获取到依赖,规范的定义可以更简单,意味着可能产生更强大的实现,这对加载器与自动化分析工具都是有利的。</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><strong>AMD 规范的弊端</strong></p><ol style="padding-left: 30px; margin-bottom: 14px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><li>依赖提前声明在代码书写上不是那么友好</li><li>模块内部与 NodeJS 的 Modules 有一定的差异</li></ol><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">关于第二点的问题需要特别说明下。其实无论是 CMD 还是 AMD 的异步模块,都无法与同步模块规范保持一致(NodeJS 的 Modules),只有谁比谁更像同步模块而已。AMD 要转换为同步模块,除了去掉<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">define</code>函数的包裹外,需要在头部使用<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">require</code>把依赖声明好,而 CMD 只需要去掉<code style="font-family: consolas, monaco, menlo, &quot;courier new&quot;, courier, monospace; display: inline-block; line-height: normal; margin-right: 0.25em; margin-left: 0.25em; padding-right: 0.4em; padding-left: 0.4em; border: 1px solid rgb(221, 221, 221); border-radius: 3px; background-color: rgb(248, 248, 248);">define</code>函数的包裹即可。</p><h2 style="font-size: 26px; margin-top: 20px; margin-bottom: 20px; counter-reset: section 0; font-weight: normal; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif;">总结</h2><table style="width: 858px; border: 1px solid rgb(220, 220, 220); border-spacing: 0px; margin: 10px auto; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;"><tbody><tr><th style="padding: 5px 10px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(220, 220, 220); border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(220, 220, 220); line-height: 2; background: rgb(252, 252, 252);">规范</th><th style="padding: 5px 10px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(220, 220, 220); border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(220, 220, 220); line-height: 2; background: rgb(252, 252, 252);">生态</th><th style="padding: 5px 10px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(220, 220, 220); border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(220, 220, 220); line-height: 2; background: rgb(252, 252, 252);">书写</th><th style="padding: 5px 10px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(220, 220, 220); border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(220, 220, 220); line-height: 2; background: rgb(252, 252, 252);">易于实现</th><th style="padding: 5px 10px; border-right-style: none; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: rgb(220, 220, 220); line-height: 2; background: rgb(252, 252, 252);">NodeJS模块相似性</th></tr><tr><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-color: rgb(220, 220, 220);">AMD</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-color: rgb(220, 220, 220);">☆☆☆☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-color: rgb(220, 220, 220);">☆☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-color: rgb(220, 220, 220);">☆☆☆☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-style: none; border-bottom-color: rgb(220, 220, 220);">☆☆☆</td></tr><tr><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-style: none;">CMD</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-style: none;">☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-style: none;">☆☆☆☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-color: rgb(220, 220, 220); border-bottom-style: none;">☆☆☆</td><td style="padding: 5px 10px; font-size: 14px; border-right-style: none; border-bottom-style: none;">☆☆☆☆☆</td></tr></tbody></table><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">从规范上来说,AMD 更加简单且严谨,适用性更广,而在 RequireJS 强力的推动下,在国外几乎成了事实上的异步模块标准,各大类库也相继支持 AMD 规范。</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">但从 SeaJS 与 CMD 来说,也做了很多不错东西:1、相对自然的依赖声明风格 2、小而美的内部实现 3、贴心的外围功能设计 4、更好的中文社区支持</p><p style="margin-top: 18px; margin-bottom: 18px; color: rgb(51, 51, 51); font-family: &quot;helvetica neue&quot;, tahoma, &quot;hiragino sans gb&quot;, stheiti, &quot;wenquanyi micro hei&quot;, 微软雅黑, 宋体, sans-serif; font-size: 16px; line-height: 27.2px;">如果有可能,我希望看到 SeaJS 也支持 AMD,与前端社区大环境保持一致最终幸福的是广大开发者。</p></div>
页: [1]
查看完整版本: 再谈 SeaJS 与 RequireJS 的差异