node前置知识点

阅读大佬笔记有感:node技术栈,总结了一些笔记

正文

  1. javascript 引擎在编译阶段会进行性能优化,很多优化依赖于能够根据代码词法进行静态分析,预先确定了变量和函数的定义位置,才能快速找到标识符,但是在词法分析阶段遇到了 with 或 eval 无法明确知道它们会接收什么代码,也就无法判断标识符的位置,最简单的做法就是遇到 with 或 eval 不做任何优化,使用其中一个都会导致代码运行变慢,因此,请不要使用with 或 eval。(eval函数接受字符串并将其转换成代码执行,with通常被当作重复引用同一个对象中的多个属性的快捷方式)

  2. typeof用来检测基本类型,instanceof用来检测数组、对象、正则

  3. 数组去重的三种方式

    1. Set数组去重,ES6新的数据结构,类似数组,但元素唯一

    2. reduce 数组对象去重,对数组中的每一个元素依次执行回调函数,不含数组中未赋值、被删除的元素,回调函数接收四个参数

      1. callback

        1. previousValue:上一次调用回调返回的值,或者是提供的初始值(initialValue)
        2. currentValue:数组中当前被处理的元素
        3. index:当前元素在数组中的索引
        4. array:调用reduce的数组
      2. initialValue:可选,作为第一次调用callback的第一个参数

    3. _.uniqBy(参考lodash:一个现代的 JavaScript 实用程序库,提供模块化,性能和附加功能)

  4. 深拷贝:

    function copy(elments){
      //根据传入的元素判断是数组还是对象
      let newElments = elments instanceof Array ? [] : {}; 
      for (let key in elments) { 
      //注意数组也是对象类型,如果遍历的元素是对象,进行深度拷贝 
      newElments[key] = typeof elments[key] === 'object' ? copy(elments[key]) : elments[key]; 
      } 
      return newElments;
    }
    
    • es6 的 扩展运算符(…) 也是可以进行深拷贝的,但好像只能拷贝一维,多维好像浅拷贝了
  5. 由于计算机底层存储都是基于二进制的,需要事先由十进制转换为二进制存储与运算,这整个转换过程中,类似于 0.1、0.2 这样的数是无穷尽的,无法用二进制数精确表示。JavaScript 采用的是 IEEE 754 双精确度标准,能够有效存储的位数为 52 位,所以就需要做舍入操作,这无可避免的会引起精度丢失。另外我们在 0.1 与 0.2 相加做对阶、求和、舍入过程中也会产生精度的丢失。

  6. js有大数处理精度丢失问题,(超过2的53次方)处理方法可以用字符串代替,如果涉及到json,可能需要使用第三方库json-bigint

  7. 如果服务端的某个数据状态定期的去变化,那么前端需要定时的去服务端取这个状态,因为 http 是无状态的链接,如果要实时的去取服务端的这种变化有两种方法,一个是长轮询,一个是通过 websocket,websocket 浏览器兼容性不好,因此长轮询还是一个普遍的用法 一种做法是通过定时器,不断的去访问接口 第二种是使用 Generator

  8. 为什么使用TS

    1. 类型安全,可以类比java
    2. TS面向对象理念,支持面向对象的封装,继承,多态三大特性
    3. 类似babel,es6,es7新语法都可以写
    4. 生产力工具的提升,vs code + TS 使IDE更容易理解你的代码
  9. TS const声明的变量必须有默认值,let声明的则不是必须的

  10. nodejs适用于什么?

    1. I/O 密集型场景

      1. Node.js 的优势主要在于事件循环,非阻塞异步 I/O,只开一个线程,不会每个请求过来我都去创建一个线程,从而产生资源开销。
    2. RESTful API

      1. 通常我们可以使用 Node.js 来做为中间层,负责组装数据提供 API 接口给到前端调用,这些数据源可能来自第三方接口或者数据库,例如,以前可能我们通过后端 Java、PHP 等其它语言来做,现在我们前端工程师通过 Node.js 即可完成,后端则可以更专注于业务开发。既然提到了 RESTful API,顺便推荐一个去哪儿开源的 API 管理工具 YAPI:https://github.com/YMFE/yapi 使用的 Node.js 进行开发的(声明下这里不是打广告,只是这个用起来真的很赞!忍不住向给大家推荐!)。
    3. RPC 服务

      1. RPC(Remote Procedure Call)中文名「远程过程调用」,也许你对它很陌生,但是在当今微服务模式下,我们可能是针对功能或者具体的业务形态进行服务化,那么服务之间的通信一种常见的模式我们都知道通过 HTTP 来实现,了解网络模型的同学可能知道,如果我们现在通过 TCP 的方式是不是会更高效呢?当然是的,HTTP 属于应用层协议,在这之下就是传输层,显然以 TCP 形式是很有优势的,RPC 服务也就是采用的 TCP,现在出名的 RPC 服务例如,Google 的 gRPC、阿里的 Dubble。
    4. 基础工具

      1. 可以做为基础工具,前端领域中的编译器、构建工具、搭建脚手架等。比较出名的例如 Webpack、Gulp 都是很成功的。
    5. 论坛社区

      1. Nodeclub 是使用 Node.js 和 MongoDB 开发的社区系统,界面优雅,功能丰富,小巧迅速,可以用它搭建自己的社区。Cnode 社区就是一个成功的例子,Cnode 地址:https://cnodejs.org/ https://github.com/cnodejs/nodeclub
    6. Backend For Frontend

      1. Backend For Frontend,简称 BFF,服务于前端的后端,并非是一种新技术只是一种逻辑上的分层,在这一层我们可以做一些资源的整合,例如:原先前端需要从三个不同的地方来获取资源,那么,有了这一层之后,我们是不是可以做个聚合,统一处理之后返回给前端,同时也不授后端系统的变迁,导致也要去更改。
    7. Serverless

      1. 这将是未来经常会听到的一个词,ServerLess 是一种 “无服务器架构”,它不需要开发者去关心运维、流量处理这些工作,开发者则可以更关注于业务本身。函数即服务,那么写一个函数就可以实现一个 API 接口给到前端,显然对开发工作是减轻了很多,在 JavaScript 中函数则是一等一的公民,在 ServerLess 这一场景下 Node.js 本身也很轻量级,还是拥有着很大的优势
    8. Microservices

      1. 微服务也是近两年一个很火热的词,这里提几个微服务主要的特点:小型服务、以独立进程运行、可以使用不同语言。那么这里则可以根据业务形态来选择不同的语言实现,Node.js 本身也是很轻量级的,实现起来也很快,在一些 I/O 密集场景还是很适用的。
  11. 本文从 Handler 处理方式、中间件执行机制的实现、响应机制三个维度来对 Express、Koa 做了比较,通常都会说 Koa 是洋葱模型,这重点在于中间件的设计。但是按照上面的分析,会发现 Express 也是类似的,不同的是 Express 中间件机制使用了 Callback 实现,这样如果出现异步则可能会使你在执行顺序上感到困惑,因此如果我们想做接口耗时统计、错误处理 Koa 的这种中间件模式处理起来更方便些。最后一点响应机制也很重要,Koa 不是立即响应,是整个中间件处理完成在最外层进行了响应,而 Express 则是立即响应。

  12. 在模块加载机制中,Node.js 采用了延迟加载的策略,只有在用到的情况下,系统模块才会被加载

  13. 在 Node.js 中模块加载一般会经历 3 个步骤,路径分析、文件定位、编译执行

  14. module.exports 与 exports 的区别?

    1. exports 相当于 module.exports 的快捷方式
    2. 但是要注意不能改变 exports 的指向,我们可以通过 exports.test = ‘a’ 这样来导出一个对象,但是不能向下面示例直接赋值,这样会改变 exports 的指向
    3. // 错误的写法 将会得到 undefined exports = { ‘a’: 1, ‘b’: 2 } // 正确的写法 modules.exports = { ‘a’: 1, ‘b’: 2 }
  15. 实现继承的方法

    1. ES6方法:class和extends关键词

    2. 原生JS:Object.setProtitypeOf().例如针对server函数和EventEmitter函数

      1. Object.setPrototypeOf(Server.prototype, EventEmitter.prototype); Object.setPrototypeOf(Server, EventEmitter);
  16. 缓存雪崩:对于需要查询 DB 的数据,我们一般称之为热点数据,这类数据通常是要在 DB 之上增加一层缓存,但是在高并发场景下,如果这个缓存正好失效,此时就会有大量的请求直接涌入数据库,对数据库造成一定的压力

  17. setImmediate() 与 setTimeout(() => {}, 0)(传入 0 毫秒的超时)、process.nextTick() 有何不同?

    1. 传给 process.nextTick() 的函数会在事件循环的当前迭代中(当前操作结束之后)被执行。 这意味着它会始终在 setTimeout 和 setImmediate 之前执行。延迟 0 毫秒的 setTimeout() 回调与 setImmediate() 非常相似。 执行顺序取决于各种因素,但是它们都会在事件循环的下一个迭代中运行。
    2. process.nextTick (),效率最高,消费资源小,但会阻塞 CPU 的后续调用;
    3.  setTimeout (),精确度不高,可能有延迟执行的情况发生,且因为动用了红黑树,所以消耗资源大;
    4.  setImmediate (),消耗的资源小,也不会造成阻塞,但效率也是最低的。
  18. Node.js 是单线程模型,但是其基于事件驱动、异步非阻塞模式,可以应用于高并发场景,避免了线程创建、线程之间上下文切换所产生的资源开销。如果你有需要大量计算,CPU 耗时的操作,开发时候要注意。

  19. 多线程的代价还在于创建新的线程和执行期上下文线程的切换开销,由于每创建一个线程就会占用一定的内存,当应用程序并发大了之后,内存将会很快耗尽。类似于上面单线程模型中例举的例子,需要一定的计算会造成当前线程阻塞的,还是推荐使用多线程来处理。线程间资源是共享的,关注的是安全问题。

  20. 关于node进程的几点总结

    1. Javascript 是单线程,但是做为宿主环境的 Node.js 并非是单线程的。
    2. 由于单线程原故,一些复杂的、消耗 CPU 资源的任务建议不要交给 Node.js 来处理,当你的业务需要一些大量计算、视频编码解码等 CPU 密集型的任务,可以采用 C 语言。
    3. Node.js 和 Nginx 均采用事件驱动方式,避免了多线程的线程创建、线程上下文切换的开销。如果你的业务大多是基于 I/O 操作,那么你可以选择 Node.js 来开发。
  21. Nodejs 多进程架构模型解决了单进程、单线程无法充分利用系统多核 CPU 的问题

  22. 守护进程:

    1. index.js 文件里的处理逻辑使用 spawn 创建子进程完成了上面的第一步操作。
    2. 设置 options.detached 为 true 可以使子进程在父进程退出后继续运行(系统层会调用 setsid 方法),参考 options_detached,这是第二步操作。
    3. options.cwd 指定当前子进程工作目录若不做设置默认继承当前工作目录,这是第三步操作。
    4. 运行 daemon.unref () 退出父进程,参考 options.stdio,这是第四步操作。
  23. 进程间是独立的关注的是通信问题,线程间资源是共享的关注的是安全问题 

  24. 孤儿进程:父进程创建子进程之后,父进程退出了,但是父进程对应的一个或多个子进程还在运行,这些子进程会被系统的 init 进程收养,对应的进程 ppid 为 1,这就是孤儿进程。

  25. IPC (Inter-process communication) ,即进程间通信技术,由于每个进程创建之后都有自己的独立地址空间,实现 IPC 的目的就是为了进程之间资源共享访问,实现 IPC 的方式有多种:管道、消息队列、信号量、Domain Socket,Node.js 通过 pipe 来实现。

  26. Node.js 是单线程还是多线程?进一步会提问为什么是单线程?

    1. 第一个问题,Node.js 是单线程还是多线程?这个问题是个基本的问题,在以往面试中偶尔提到还是有不知道的,Javascript 是单线程的,但是做为其在服务端运行环境的 Node.js 并非是单线程的。
    2. 第二个问题,Javascript 为什么是单线程?这个问题需要从浏览器说起,在浏览器环境中对于 DOM 的操作,试想如果多个线程来对同一个 DOM 操作是不是就乱了呢,那也就意味着对于 DOM 的操作只能是单线程,避免 DOM 渲染冲突。在浏览器环境中 UI 渲染线程和 JS 执行引擎是互斥的,一方在执行时都会导致另一方被挂起,这是由 JS 引擎所决定的。
  27. 多进程或多个 Web 服务之间的状态共享问题?

    1. 多进程模式下各个进程之间是相互独立的,例如用户登陆之后 session 的保存,如果保存在服务进程里,那么如果我有 4 个工作进程,每个进程都要保存一份这是没必要的,假设服务重启了数据也会丢失。多个 Web 服务也是一样的,还会出现我在 A 机器上创建了 Session,当负载均衡分发到 B 机器上之后还需要在创建一份。一般的做法是通过 Redis 或者 数据库来做数据共享。
  28.  Net 与 Dgram 是基于网络模型的传输层来实现的,分别对应于 TCP、UDP 协议

  29. TCP 粘包是什么?该怎么解决?

    1. 客户端(发送的一端)在发送之前会将短时间有多个发送的数据块缓冲到一起(发送端缓冲区),形成一个大的数据块一并发送,同样接收端也有一个接收端缓冲区,收到的数据先存放接收端缓冲区,然后程序从这里读取部分数据进行消费,这样做也是为了减少 I/O 消耗达到性能优化。

    2. TCP 粘包解决方案?

      1. 方案一:延迟发送
      2. 方案二:关闭 Nagle 算法
      3. 方案三:封包 / 拆包 : 通信双方约定好格式,将消息分为定长的消息头(Header)和不定长的消息体(Body),在解析时读取消息头获取到内容占用的长度,之后读取到的消息体内容字节数等于字节头的字节数时,我们认为它是一个完整的包。

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。