JavaScript 代码热替换.doc_第1页
JavaScript 代码热替换.doc_第2页
JavaScript 代码热替换.doc_第3页
JavaScript 代码热替换.doc_第4页
JavaScript 代码热替换.doc_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JavaScript 代码热替换题叶我花了不少时间去学习 JavaScript 的代码热替换技术,上周把 Webpack 的结果录了一个视频, 这周又把相同方案在 Figwheel 环境当中粗糙地实现了一遍, 如果关注这方面的进展可以往细了看一看, 只是我的代码都基于 Cirru 也许不方便入手. 总之, 对于热替换技术我积攒了很多的感想, 可以凑一篇文章来笼统说一下.另外在知乎上补了一个问题, 如果有兴趣挖历史的话可以一看:有过哪些代码热替换的技术? - 编程语言. 我接触编程挺晚, 2009 年冬天大致对 HTML Python 有了点概念, 到 2012 年知乎上膜拜了 Haskell, 渐渐开始摸到了现在的方向, 并且关注新技术, 旧的历史我恐怕不了解, 等待高人挖出来.过去抢镜的前端代码热替换 做前端开发, 接触到热替换的需求挺多的, 最初是在浏览器调试工具元素界面上直接修改 CSS 属性, 或者直接替换掉 JavaScript 运行环境的变量. 然后 Chrome 开始发力, 在 Workspace 工具当中集成热替换功能, 比如 2013 年 IO 大会上演示 CSS 文件直接编辑生效, 并且后来通过 Source Map 支持的了 LESS 和 SASS 等. 同时 JavaScript 文件的热替换也在 Remote Debugging Protocol 当中支持, 在 Workspace 中修改的函数会自动替换掉正在运行的代码当中. 就我所看到的, Chrome DevTools 团队牛人真是高歌猛进. 基于 Webkit 调试工具的热替换功能后来还被发挥得更漂亮. LightTable 原本是基于 node-webkit 开发的 IDE(现在已经切换 Electron 了, 也是 Webkit), LightTable 用于演示 JavaScript 开发的例子, 当时就是打开了一个 WebGL 的调试页面,一边修改 JavaScript, 一边画布上的粒子组成的立方体在更新, 同时不会破坏它的旋转状态. 至少对于开发而言是垂涎的. 另一个方向上也有人把 Remote Debugging Protocol 扒出来开发新的工具叫做Amok, 于是你可以在浏览器外边普通的 Text Editor 当中用了. 反过来也见过Sublime Web Inspector这样的项目把整个调试工具搬进编辑器, 有点疯狂. 到了 LightTable 当然绕不过Bret Victor 大神的 Invent on Principle 演讲了,在 LightTable 之前作者了若干篇博文都是和 Bret Victor 大神的东西相关的, 不细说了. 后来大家都看到 2014 年 WWDC Swift 发布时演示的 Playground, 太多太多 LightTable 影子, 然而我不了解 Swift 开发不晓得热替换在 Swift 当中能走到什么程度? JavaScript 这边激发的项目项目还有Tangle, 这是一个动态修改文档的类库, 也蛮有意思. 前面提到了 SASS, 也就是编译到 CSS 的语言, 在浏览器当中实现了热替换, 而编译到 JavaScript 的语言也同时在发展着, 而且其中的替换也远远不是编译到 JavaScript 然后动态 patch 掉 runtime 那么直接, 毕竟这仅仅是 Webkit 当中带的功能. 专业的函数式语言比如 Haskell 和 Clojure 编译出的 JavaScript 普通人恐怕觉得还不如 ASM.js 来的像 JavaScript. Elm 靠的是纯函数代码, 直接进行函数替换.Elm 语言热替换的文章回溯到 2013 年九月, 作者演示了一个网页游戏当中, 修改代码角色跳跃轨迹动态修改的例子, 两年多之前, 那可是非常震撼的. 后来 Elm 做得越来越细, 时间旅行调试, 智能提示编译错误, 俨然甩开频繁刷新页面的我们很多年. ClojureScript 也是编译到 JavaScript 的函数式语言, 热替换实现得有点晚, Figwheel 在大会上亮相的时间还在 Webpack 很久之后, 只是后来能和 Webpack 的热替换抢抢风头, 比如说在Unity 的 VR 环境当中热替换代码编程, 而且 Figwheel 也跟着 React Native 一起用 ClojureScript 在 Android 和 iOS 做热替换. 我没研究细节实现, 也说不上来, 据说已经能做到一份 Om 代码, 同时热替换 Web, iOS, Android 三个平台. 它的角色和 JSX 也蛮像的, 一方面提供语法做静态分析和提示编译错误, 一方面生成 JavaScript 和 Virtual DOM 去对付 Native 平台的环境. 跳出 JavaScript 来说, 热替换大概是早已存在的技术, Erlang 在 1987 年发布的, 我不清楚支持的时间但是很早就是支持了代码的热替换, 当然纠正一下, 并不是说开发时热替换代码, 而是部署 OTP 应用时不需要整个杀掉旧的服务, 只需要逐步替换成新的进程就好了. Elixir 建立在 Erlang VM 之上, 自然也继承了这个特性. 我不大了解其他语言在这方面,看到 Android Studio 有支持热替换的消息, 具体不清楚. 开发环境热替换代码对于延续 C 风格的静态类型语言来说并不容易, 只是对于那些消耗性能的脚本语言来说有点意思, 比如 Lisp 系语言(我主要接触 Scheme 和 Clojure)随语言附带的 REPL 环境, 当中可以动态加载代码, 比如 Clojure 的 REPL 可以声明 :reload 参数重新加载 namespace(Scheme 方面以及 Common Lisp 方向倒是不清楚). 而流行脚本语言中Node.js 可以神奇地手动清除缓存重新加载代码, Python 似乎也是类似, 而Ruby Pry 似乎也有不俗的效果. Smalltalk 由于自带开发环境, 倒是可以在运行时中编辑替换掉方法. 而CommonLisp 只是大概看过 OpenGL 上热替换的例子, 而Lua 游戏界面可能是基于 Love, 也有相似热替换的方案. 花时间扒一下大概有不少.Webpack 和 React 我记得 Webpack 热替换模块出名是在 2014 年下半年的样子, 相对于以往的前端打包工具而言, Webpack 很让人赞叹的一点是所有的模块资源被抽象成了 module, 从而在 Webpack 打包时所看到的是大量 Module 形成的 Graph, 而不是单纯的文件. 在这个 Graph 当中, 一个文件被修改, 就是类似于一个更新事件, 这个事件随着 Module 依赖关系一层层往上传递, 一直到被捕获, 或者传递到根节点引发一次页面刷新. 实际上通过 Webpack 提供的 API, 很容易你就能插入捕捉事件的代码, 进行 Module 的热替换. 在这个前端项目被越码越大且没有二进制文件不成熟的背景之下, Webpack 提供的热替换方案十分宝贵. 我们在开发的单页面初次加载代码也许随着 CPU 性能, API 网络瓶颈, DOM 初始化因素, 导致每一行代码修改都可能依赖数秒钟的界面重载和环境的重现, 而在热替换的情况下加上固有的文件监听延时可能几秒就好了, 成倍地压缩了时间改善着工作效率. 更可贵的是 React Native 跟着把战火烧到了 iOS 和 Android 两个平台, 导致许多小公司在开发跨平台应用时机灵地盘算着省掉一半多开发者的可能性. 对于前端来说, Webpack 的成功促使了 browserify-hmr 的出现, 又多了一个热替换的方案. 给 react-hot-loader 接班的大概是 Redux 方案, 也就是 Elm 给的方案(也许很多游戏应用早就做了, 只是我外行), 就是限制在全局的可变状态, 搭配尽可能不存储状态的渲染代码. 前端的代码热替换主要是替换渲染的逻辑, 打头阵的 CSS 替换甚至都不是 JavaScript 运行时中间需要对付的问题, 随后是 JavaScript 函数本身的替换, 后面 Virtual DOM 方案将可变状态的 DOM 做了抽象的封装促成了 DOM 结构能随着 JavaScript 数据做替换. Redux 也开始替换到了数据更新所使用的代码. 有点跑题, 但是注意, 热替换的不是数据, 而是逻辑, 或者说描述转换或者过程的函数. 当一段代码被完全替换时, 实际上不仅仅是代码, 包括所有原先的代码造成的所有效果, 都需要被清理掉, 从函数式编程的思路来说函数的效果, 一是返回结果, 一是副作用也就是除了返回值之外的状态操作(比如往外部作用域赋值, 比如写文件). 其中函数返回结果, 或者在外层函数被使用, 或者被垃圾回收, 不急着考虑. 而副作用, 两个对策, 一个是 Elm 限制程序使用纯函数隔隔离作用, 一是Webpack dispose 方法你自己去写回滚副作用的代码. 从而在新的代码加载时就像是跟全新环境一样执行. 另一个问题是开发的代码产生的破坏性效果, 比如 Error 对整个进程的杀伤力恐怕不是 dispose 里写点代码能控制牢的. 也有一些办法, 主要是静态分析, 比如 Elm 模仿 Haskell 的 ADT 分析, JSX 对语法和 PropTypes 的静态检查, ClojureScript 基于 Google Closure Compiler 实现的静态分析, 至少思路都一致, 就是有问题的代码尽可能早一点察觉, 根本不予执行. 即便进程出问题了, 重要的是核心的全局状态数据不能丢, 总是有办法把整个运行时重新生成出来的. 在这样的套路之下, 函数式编程的纯函数和隔离状态, 就大展身手了. 毕竟没写一段代码, 比如服务器上注册一个 router handler, 当它的代码被替换需要清除时, 又需要手动调用 server.removeListener 去掉 old handler 然后注册 new handler, 而且一个 server 有几十个路由, 这种麻烦事情谁喜欢做, 还不如一开始就采用纯函数的手段来得痛快, 最终只要把更新的代码分成几大块, 针对性得一起处理了就好了. 而且在函数式语言的严格限制当中, 副作用也是少之又少, 需要担惊受怕的奇怪代码也可以放心一点. 我不吐槽 JavaScript 转而吹捧 Clojure, 并不是后者一定更方便, 但前者这种散漫多变实在让我不能放心托付. 今天微博上说了, ClojureScript 和 Figwheel 环境乍一操作起来, 坑比起 Webpack 还要多一些, 不深入说了, 大致上 Cirru 语法倒没什么问题, 而是惰性计算和 atom 的引用上有我这个新手不理解的地方. ClojureScript 编译时相比 JavaScript 能检查命名空间, 变量定义, 参数个数, 同时限制了可变数据使用也就避开了大部分旧代码副作用而能够直接进行替换(更像是 Amok 用 Remote Debugging Protocol 对 JavaScript 函数 body 代码进行替换那样), 只是更丰富的数据类型和功能确实带来了难度. 前面我用 Webpack 和 Figwheel 搭建的环境, 一来是前端 DOM 渲染采用热替换, 避免破坏 Store 和 WebSocket 的连接状态, 二来是服务端数据更新采取了热替换, 避免了Database(我直接用的内存)和 WebSocket 的状态被破坏. 我采用的Cumulo 方案前端数据几乎完全从后端同步, 意外着如果我将 Database 独立于进程做一些持久化, 即便重启进程也能恢复整个环境. 至少验证了一套方案, 大多数情况可以做到在添加新功能, 增加对应数据处理逻辑, 的过程当中不需要重启服务器或者刷新浏览器页面, 局部替换代码就好了.若干年后本来我因为害怕打算只专心写写东西, 然而看多了近些年的自频道对创业潮也开始绷起了神经. 当人们在推动大量的年轻人去在互联网创业, 国内出现像是雷军这样谋大局的企业家让小米快速膨胀, 也出现我厂 CEO 这样的新秀的时候, 给一个成功企业家配备的可不仅仅是几个程序员对吧, 首先需要投入大量的码农写业务, 其次投入大量的研究者想办法放大码农的技能压缩其数量. 简单说, 代码需求越来越大, 单兵的产量也越来越高. 环境就像是气球正在被吹大, 想想看, 气球吹大之后你我分别被映射到哪个位置?思绪有点乱, 换个问法, 你在写服务器, Java, 报错, 修改, 编译, 运行, 几分钟过去了, 然而别人用 Go 改了一分钟, 几秒钟编译出结果了. 或者你在写 HTML, 样式不对, 快捷键换窗口, 改一下代码, 刷新页面, 终于做完了界面, 然而别人用 Pixate 直接生成了页面交互出来. 然后主管过来问进度, 又说为什么别人能做出来你做不出来, 那你为什么不学? 面对的现象差不多, 帐怎么算是每个人不同的事情, 心累.若干年前, 事情简简单单, 你从高考跌进社会, 所见所得想做一些事情. 就像Bret Victo

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论