# 前端

# npx

npm 从 5.2 版开始,增加了 npx 命令。它有不少用处,但很多人其实又不知道它是个什么,该如何正确的使用它。

Node 自带 npm 模块。所以你只要安装了 node,你就可以直接使用它了,不需要什么额外的操作。

# 方便调用

npx 第一个好处就是方便的调用了项目内部安装的模块。比如我项目内安装了测试工具 Mocha。

npm install -D mocha

般来说,调用 Mocha ,只能在项目脚本和 package.json 的 scripts 字段里面, 如果想在命令行下调用,必须像下面这样。

# 项目的根目录下执行
node-modules/.bin/mocha

npx 就是想解决这个问题,让项目内部安装的模块用起来更方便,只要像下面这样调用就行了。

npx mocha

它的原理也很简单。就死运行的时候会到node_modules/.bin路径和环境变量$PATH里面,检查命令是否存在。

# 避免全局安装

第二个好处就是可以避免全局安装模块。比如,你要用 react 的脚手架create-react-app它是需要全局安装的,但你其实也只有在初始化的时候需要用到它,大部分时间它是使用不到的。 但用了 npx 之后,就不需要全局安装它了。你可以使用 npx 直接运行它。

npx create-react-app my-react-app

上面代码运行时,npx 将create-react-app下载到一个临时目录,使用以后再删除。所以,以后再次执行上面的命令,会重新下载 create-react-app

# 指定版本

npx 还有一个好处,就是你可以指定你要运行模块的版本。比如你本地环境是 node10 的,但你想用 node11 的环境执行一段脚本。(当然你也可以 nvm 本地管理多个 node 版本)

npx -p node@11.9.0 node -v

# 垃圾回收

2019.05.30

作为编写程序的人,是可以做出“这个对象已经不再需要了”这样的判断,但计算机是做不到的。因此,如果程序(通过某个变量等等)可能会直接或间接地引用一个对象,那么这个对象就被视为“存活”;与之相反,已经引用不到的对象被视为“死亡”。将这些“死亡”对象找出来,然后作为垃圾进行回收,这就是 GC 的本质。

三大基础 GC 算法

https://juejin.im/entry/5d2ee41af265da1b7004defd

# 引用计数法

它的基本原理是,在每个对象中保存该对象的引用计数,当引用发生增减时对计数进行更新。引用计数的增减,一般发生在变量赋值、对象内容更新、函数结束(局部变量不再被引用)等时间点。当一个对象的引用计数变为 0 时,则说明它将来不会再被引用,因此可以释放相应的内存空间。

引用计数最大的缺点,就是无法释放循环引用的对象。

# 标记清除法/标记压缩法

这个算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象

从 2012 年起,所有现代浏览器都使用了标记-清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义。

标记清除算法有一个缺点,就是在分配了大量对象,并且其中只有一小部分存活的情况下,所消耗的时间会大大超过必要的值,这是因为在清除阶段还需要对大量死亡对象进行扫描。

三色标记 大部分使用该算法。现代 JS 引擎的垃圾回收算法都已经不是简单的活跃与否的 mark

  • 状态为白(white), 它尚未被垃圾回收器发现
  • 状态为灰(gray), 它已被垃圾回收器发现,但它的邻接对象仍未全部处理完毕
  • 状态为黑(black), 它不仅被垃圾回收器发现,而且其所有邻接对象也都处理完毕

# 复制收集算法

在这种算法中,会将从根开始被引用的对象复制到另外的空间中,然后,再将复制的对象所能够引用的对象用递归的方式不断复制下去。

但是,和标记相比,将对象复制一份所需要的开销则比较大,因此在“存活”对象比例较高的情况下,反而会比较不利。这种算法的另一个好处是它具有局部性(Lo-cality)。在复制收集过程中,会按照对象被引用的顺序将对象复制到新空间中。于是,关系较近的对象被放在距离较近的内存空间中的可能性会提高,这被称为局部性。局部性高的情况下,内存缓存会更容易有效运作,程序的运行性能也能够得到提高。

# 分代回收

V8 引擎将保存对象的 堆 (heap) 进行了分代:

  • 对象最初会被分在 新生区(New Space) (1~8M),新生区的内存分配只需要保有一个指向内存区的指针,不断根据内存大小进行递增,当指针达到新生区的末尾,会有一次垃圾回收清理(小周期),清理掉新生区中不再活跃的死对象。

  • 对于超过 2 个小周期的对象,则需要将其移动至 老生区(Old Space)。老生区在 标记-清除 或 标记-紧缩 的过程(大周期) 中进行回收。

大周期进行的并不频繁。一次大周期通常是在移动足够多的对象至老生区后才会发生

参考:

# Virtual DOM 性能好?

每次面试,面试人一谈到 react 就必然会谈到 Virtual DOM,一谈到 Virtual DOM 就会说它比原生操作 DOM 性能哪里哪里好。

但任何一个 v-dom 框架都不会说自己的性能快过 DOM 操作。就拿 react 为例子,它的目标是:“每次数据变化都以最小的代价来更新真实 DOM”。引入 v-dom,在内存中比较虚拟节点,然后找出不同,之后执行更新。

就能更改页面上一个元素的内容,直接操作 DOM 的反应速度绝对会比你 diff 一次之后再更新来的快。但这时你可能会觉得当程序到达一定的复杂度之后,v-dom 性能上的优势才能体现出来。但是,无论你代价再少也好,v-dom 都是有消耗的,光从你要生成整个页面的 v-dom 就会比单单生成原生 dom 要多消耗一大截内存,更别说其中的复杂递归,比对,然后再变换。但是!它依然是纯 js 层面的计算,比起后面的 DOM 操作来说,依然便宜了太多。

所以 v-dom 真正的价值是什么?

框架给你的保证是,你在不需要手动优化的情况下,我依然可以给你提供过得去的性能。

我认为是带来了跨屏能力,以及代码的可维护性, 同时为函数式的 UI 编程方式打开了大门。

上次更新: 11/14/2019, 3:15:12 AM