`
limu
  • 浏览: 321195 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

如果给JS代码发布正式使用前增加一个编译步骤,我们能做些什么.

阅读更多
最近看了Hedger Wang的"Coding Better Object-Oriented JavaScript with Closure Compiler"(中文),算是给D2预热.终于明白Google这工具为啥叫Compiler而不是Compressor.

相对于编译型语言,JavaScript缺少了编译这个环节.传统编译器把代码转换为可执行的机器指令的动作交由浏览器中的JS引擎在运行时执行.但现代的编译器除了代码翻译还有哪些功能?而JS引擎能在运行时Cover住这些任务么?

最常见的运行时编译无法解决的问题就是代码压缩.所以我们有各种Compressor让代码传输给浏览器的时是最小的.
而在这篇文章中Google Closure Complier告诉我们还可以在编译时统一OO风格,减小对象深度以提高访问速度,使用枚举,常量等等其他语言好用的特性.

但看了文章之后我还是没有马上使用GCC这些高级功能的打算.
预编译时只能做这么多么?
我觉得Google Closure Complier更有意义的是告诉我们,可以有这样一个发布前预编译的步骤,可以有这样的一个时间窗口,在这个时候结合我们自己的应用,结合我们自己遇到的问题是不是也可以做点什么.

最近我在做kissyLite,前一篇文章kissyLite的包管理和无需预先注册的带依赖关系模块异步加载,讲的是用较少的代码为JS引入具有良好扩展性的模块化.就这个应用场景,我们可以在预编译的环节做点什么.

场景一

mod开发者开发一个功能,将它封装在mod-a中.
然后我们发现mod-a中可以抽象出来mod-b,让mod-b其他地方也能使用到.
于是就有了mod-b,同时mod-a requires mod-b.

mod使用者的代码始终是KSLITE.use('mod-a',function(){});

由于原有mod-a被拆分,就需要串行的加载mod-a,mod-b.
因为以kissyLite的模块化模式,在mod-a加载进来之前是不清楚它require mod-b的.

为了颗粒化可重用,造成了性能的损失 -- 多了一个请求,而且是串行的.

通过预编译能解决这个问题么?可以.

模块使用者,使用Debug(带预编译相关功能)版本的kissylite,控制台就可以给出两个优化建议:
"为了让子模块能够平行加载,你应该修改此处代码为KSLITE.use('mod-a,mod-b');!"
可见至少我们解决了平行加载的问题.
而且我们可以在开发的时候完全不去考虑这个问题,当所有功能做好之后再来优化,这其实就是预编译时优化功能.

场景二

mod开发者还是发现mod-a中可以抽象出来mod-b,让mod-b其他地方也能使用到.
这次他非常清楚过细的颗粒化会引入更多的请求和串行加载等性能问题.
所以他在纠结到底要不要为了可能的重用单独先提出来mod-b.

通过预编译能解决这个问题么?如果预编译模块能结合自动化测试和自动构建,可以
首先回答:要将mod-b拆出来!
当我们把当前应用所有重要的测试用例都跑过一遍之后,发现当前的所有应用场景mod-b都是跟着mod-a进来的.
那么预编译可以给出优化建议
"为了减少请求数,可以将mod-b的内容追加到mod-a的后面".
因为mod-a必须要叫上mod-b,而当前mod-b还没有被单独使用,不如合并.
甚至可以结合自动构建工具,给出最适合当前应用的kissy版本kissy4U.
"为了减少请求数,这次构建已经吧mod-b的内容追加到mod-a的后面:)".
基准的kissy版本,mod-a和mod-b每个都是独立的.
而在为你应用构建的kissy4U中,mod-b在mod-a文件中.
不用纠结提出mod-b引入的性能问题了,写最优雅的代码吧.

场景三
还是mod-b要不要跟着mod-a一同输出.
现在问题又变化了,mod-b可能被单独使用,也可能被mod-a调用.
还要不要合并mod-a mod-b 到mod-a.js呢?
到底是先use mod-b 再 use mod-a的情况多呢?(这样显然不要合并文件)
还是直接就use-a的情况多呢?(这样还是合并了好点)

通过预编译能解决这个问题么?如果预编译模块能结合线上实际使用情况的统计反馈数据,可以.
我们参见Facebook的静态网页资源的管理和优化
我们有了抽样统计数据的反馈,就可以在预编译阶段根据反馈来决定要不要合并mod-a和mod-b.

场景四
add时到底要不要attach?
add的重要功能是注册一个模块,当这个模块不依赖其他模块或所依赖的内容都可用.那就具备attach的条件,要不要attach呢?
如果attach了,use的时候更快.如果不attach,页面加载更快.

回答问题:add的时候不要attach.
默认attach引入的代码运行消耗是不必要的.微软还有一个专门的工具Doloto来拆分加载时必要的代码和不必要的.

但这样做use的时候可能就会慢了.尤其use还可能涉及异步模块加载...
跟随微软的思路我们很容易想到办法,在domready之后,浏览器不忙的时候把可能用到的模块预先attach.
我称这个动作为预热.那该预热哪些?页面上有几十个功能都预热么?

通过预编译能解决这个问题么?依然可以.
在页面开发完之后把将会常用的功能使用一遍.然后编译器就可以给出提示.
"应该在domready的之后use('a,b,c,d'),进行预先attach".
即domready前按需加载,domready后选择性预热.

预编译打开一扇窗
可以看到针对kissyLite这个具体的应用:
        利用好这个环节,模块开发者的模块的划分,不必再因为性能问题而纠结.
        利用好这个环节,应用开发者可以配置出最优的代码打包方案,如Facebook做的那样.
        利用好这个环节,模块化架构可以不必纠结add时attach影响页面速度,不attach又拖慢功能使用.
但这不重要,可能没有一条适合你.

我们看到Hedger Wang在文章开头先抱怨了一通,然后使用GCC解决了这些问题.
而这里给出的几个场景完全不同,又何其相似.
我们也抱怨一通,然后经GCC启发,在其引入的预编译阶段也解决了这些问题.

每个应用都会遇到自己独特的问题被抱怨,也能在预编译这个时间窗口解决一些什么么?

分享到:
评论

相关推荐

    Kettle源码编译流程说明

    Kettle源码编译流程说明,描述怎么编译kettle的源代码,以及遇到的问题解决方法

    JAVA上百实例源码以及开源项目源代码

    同时一个mail note将被发送给消息发送者,发送一个e-mail通知给由recipient参数确定的e-mail账号,查询mail 服务器的会话……  还包括消息客户端程序,通过连接创建会话。创建发送者和映射消息。发送消息,同时对...

    阿里云OSS ali-oss 6.0 npm代码包带案例修复版本 编译打包js,可以直接引入使用

    官方的git代码库,给的example是5.x版本案例,并且官方使用npm run build-dist打不了包,可能代码太过来老旧; 案例中OSS.wrapper属于6.x以下版本,已改为OSS方式,采用实际子账户进行分片上传,发现没有问题; 操作...

    使用Node.js写一个代码生成器的方法步骤

    自己写一个的原因是因为要集成到自己写的一个小工具中,而且使用 Node.js 这种动态脚本语言进行编写更加灵活。 原理 代码生成器的原理就是: 数据 + 模板 => 文件 。 数据 一般为数据库的表字段结构。 模板 的语法...

    JAVA上百实例源码以及开源项目

    同时一个mail note将被发送给消息发送者,发送一个e-mail通知给由recipient参数确定的e-mail账号,查询mail 服务器的会话……  还包括消息客户端程序,通过连接创建会话。创建发送者和映射消息。发送消息,同时对...

    JavaScript 详解预编译原理

    JavaScript 预编译原理 今天用了大量时间复习了作用域、预编译等等知识 看了很多博文,翻开了以前看过的书...传统的编译会经历很多步骤,分词、解析、代码生成什么的 日后有时间再给大家科普 下面就给大家分享

    vue-devTool编译和安装教程附源代码和编译后的安装包

    vue-devTool编译和安装教程附源代码和编译后的安装包。 根据实操完整的操作步骤。

    java源码包---java 源码 大量 实例

    同时一个mail note将被发送给消息发送者,发送一个e-mail通知给由recipient参数确定的e-mail账号,查询mail 服务器的会话……  还包括消息客户端程序,通过连接创建会话。创建发送者和映射消息。发送消息,同时对...

    js-linker:一个库,用于在js代码中搜索require调用,并将它们链接到一个脚本中

    js链接器 一个库,用于在js代码中搜索require调用,并将它们链接到一个脚本中。 该工具可以在node.js或浏览器中使用。 这是一个与browserify相似的编译步骤。高级API 高级接口使用加载程序功能和初始的bootstrap js...

    javascript入门笔记

    条件是一个boolean类型的数据,如果条件结果为true,则执行表达式1的内容,并将表达式1的结果作为整体表达式的结果。如果条件为false,则执行表达式2的内容,并将表达式2的结果作为整体表达式的结果 ex: var age ...

    java源码包2

    同时一个mail note将被发送给消息发送者,发送一个e-mail通知给由recipient参数确定的e-mail账号,查询mail 服务器的会话……  还包括消息客户端程序,通过连接创建会话。创建发送者和映射消息。发送消息,同时对...

    React Native打包IOS超详细步骤

    项目名我们设定为:iotApp 1、在ios目录下新建bundle目录。后面编译打包离线资源,也会生成bundle目录,提前建,是为了防止某些情况下报错。... --dev false //设置为false时会对JavaScript代码进行优化处理

    压缩Vue.js打包后的体积方法总结(Vue.js打包后体积过大问题)

    由于这次项目是在初学 Vue 之后的第一个正式项目,没有考虑到类似 路由懒加载、 按需加载的问题 ,所以呢,也算是没经验。 到了这些天,项目写得差不多了,准备放到服务器测试,才发现这个问题。 优化前: app.js ...

    使用pkg打包Node.js应用的方法步骤

    Node.js应用不需要经过编译过程,可以直接把源代码拷贝到部署机上执行,确实比C++、Java这类编译型应用部署方便。然而,Node.js应用执行需要有运行环境,意味着你需要先在部署机器上安装Node.js。虽说没有麻烦到哪里...

    django-ember-precompile:用于使用 django 压缩器的项目的 ember.js 预编译器

    django 项目有一个使用 django 压缩器执行代码的快速钩子 如果可能,我更喜欢为 ember.js 预编译我的车把模板 我找不到与 django 压缩器和 ember.js 一起使用的现有 npm 模块 ##那我该如何开始? 首先你需要安装 ...

    JS API接口和返回的版本

    目前所有版本的JS JSP ASP .NET J2AM 都是提供源代码的,对于一些脚本语言来说,直接解压缩之后就可以使用了,不需要什么安装步骤。另外一些需要编译的语言,则提供了编译用的 shell 文件(Linux/Unix 下使用)和 ...

    liquid.js:Tobias Luetke的Liquid模板引擎JavaScript端口

    Liquid.js 一般的 这是从Ruby到JavaScript的完整移植。 Ruby Liquid可以编译和呈现的任何模板,Liquid.js也应该如此。 这试图与javascript框架无关(即不使用jQuery也不使用Prototype)。 这将增加一些额外的代码,...

    compile-nt:一个在线IDE,可以为您编译代码

    这是一个在线IDE,可在竞争激烈的编程中为您编译用不同语言编写的代码。 要使用,请确保已安装节点。 请按照给定的步骤进行操作: 1. Clone this repository. 2. cd into the repository. 3. Open Terminal from...

    JSP动态网页制作基础培训教程源代码.rar

    读者可根据相应的使用说明直接使用这些源代码。 一、基础知识部分 此部分是指文件夹名为第1~9章中的内容(如表1),这些是书中介绍JSP相关知识的源代码。文件的命名规则与书中相应源代码文件名一致。读者可将相关...

Global site tag (gtag.js) - Google Analytics