我是靠谱客的博主 会撒娇鸵鸟,最近开发中收集的这篇文章主要介绍nodejs整理js基础node,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

这里写目录标题

  • js基础
    • bind call apply区别
    • this
    • 原型
    • promise 源码解读
  • node
    • 特点
    • 适用于场景
    • 重要模块
      • event
      • stream
      • net
      • buffer
      • child_process(spawn exec execFile fork)
      • crypto
    • node 内存管理
      • v8堆内存限制
      • 新生代和老生代。
      • 新生代空间&Scavenge算法
      • 老生代空间&标记清楚(Mark-Sweep)和标记整理(Mark-Compact)算法以及增量标记(incremental marking)技术
    • 内存泄漏
      • 全局变量
      • 闭包
      • 慎将内存做为缓存
      • 模块私有变量内存永驻
      • 事件重复监听
      • 其它注意事项
      • 内存泄露的检测(memwatch & heapdump)
    • node 事件循环
    • 优先级
    • Node.js 的构成
    • node 性能优化
    • node 常用框架
      • koa2
      • express
      • egg
      • nest

js基础

bind call apply区别

  • 都是改变函数的this指向;
  • call, apply调用函数, bind 返回一个新的函数;
  • call方法除了第一个参数以外的参数是以参数列表形式, apply的第二个参数是个参数数组;
  • bind 的参数可以在调用返回的函数的时候传参;

this

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。

原型

  • 每个对象都有一个原型对象(null除外),从原型对象继承属性,_proto_属性指向原型对象;
  • 每个对象的构造函数的prototype属性指向原型对象,指向的原型对象是和对象的_proto_属性是同一个;
  • 每个原型对象都有一个constructor属性,指向该关联的构造函数
  • 当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。(即从原型链上查找属性)
  • Object的原型对象的原型为null, 即Object.prototype.proto === null。

avatar

promise 源码解读

  • 首先Promise构造函数会立即执行,而Promise.then()内部的代码在当次事件循环的结尾立即执行(微任务)。
  • promise的状态一旦由等待pending变为成功fulfilled或者失败rejected。那么当前promise被标记为完成,后面则不会再次改变该状态。
  • resolve函数和reject函数都将当前Promise状态改为完成,并将异步结果,或者错误结果当做参数返回。
  • 构造函数传入函数作为参数, 该函数中的两个参数resolve,reject 是Promise内部的方法,主要是迭代执行onResolvedCallbacks和onrejectedCallbacks中的方法;
  • then 方法能链式调用的原因:返回新的Promise对象, then方法的两个参数onfulfilled和onrejected根据当前Promise的状态来执行或放入onResolvedCallbacks和onrejectedCallbacks中;

ES6 Promise源码解析 (从Promise功能的角度看Promise源码实现)

node

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。

特点

  • 异步/IO
  • 单线程
    Node.js的单线程指的是主线程是“单线程”, 只有js执行是单线程,I/O显然是其它线程。
  • 事件和回调函数
  • 跨平台

适用于场景

  • I/O 密集型场景
  • RESTful API
  • RPC 服务
  • 基础工具
  • 论坛社区
  • Backend For Frontend(前后端分离)
  • Serverless(无服务器架构)
  • Microservices(微服务)

重要模块

event

  • this 的问题, 箭头函数中this指向空对象,function声明的函数中this指向监听器所附加的 EventEmitter。
  • 获取和修改最大事件监听数量
  • EventEmitter 以注册的顺序同步地调用所有监听器。
  • 如果没有为 ‘error’ 事件注册监听器,则当 ‘error’ 事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。应该始终为 ‘error’ 事件注册监听器。
  • 监听不用要remove掉
    event模块整理

stream

  • 特点: 1. 边读边写;2. 事件特性
  • 类别:可读流、可写流、双工流、转换流。
  • 流的缓冲:可写流和可读流都有自己的缓冲,缓冲大小由构造参数highWaterMark决定。
  • 流的对象模式:nodejs的流默认运作在字符串、Buffer或Unit8Array上。若流使用了其他的Javascript值,这些流会以“对象模式”运行。 创建流时,用objectMod哦可以把流切换到对象模式。
  • 流的管道(pipe)方法:readable.pipe(writable);
    stream模块整理

net

我们先来说一下TCP与ICP的异同:

TCP/IP-传输控制协议/网际协议地址;可在同一台机器或不同机器或不同操作系统的进程间进行通信;

IPC (Inter Process Communication) 即进程间通信;不能跨物理机器,只能在同一台机器上的不同进程间进行通信;

在同一台机器上的两个进程间进行通信两者都可以使用,但是IPC效率会高于TCP/IP,原因:前者是直接把通讯包给另一个进程,后者是先把通讯包给本地环路接口,再从接口给另一个进程;

Net模块主要是两个类:Server、Socket。

buffer

Buffer是node的核心模块,开发者可以利用它来处理二进制数据,比如文件流的读写、网络请求数据的处理等。

创建:

  • new Buffer(array)
  • Buffer.alloc(length)
  • Buffer.allocUnsafe(length)
  • Buffer.from(array)

child_process(spawn exec execFile fork)

  • spawn fork 没有回调,exec execFile 有回调。spawn 是其他方式的基础。
  • exec 会调用shell程序执行命令,execFile默认不调用shell。
  • fork 专门用于衍生新的 Node.js 进程,返回的子进程将内置一个额外的ipc通信通道,允许消息在父进程和子进程之间来回传递。

crypto

node利用 OpenSSL库来实现它的加密技术,这是因为OpenSSL已经是一个广泛被采用的加密算法。

crypto模块整理

node 内存管理

v8堆内存限制

node 使用js会有内存限制:64 位系统下约为 1.4 GB,32 位系统下约为 0.7 GB。造成这个问题的主要原因在于 Node 基于 V8 构建,V8 的内存管理机制在浏览器的应用场景下绰绰有余,但在 Node 中却限制了开发者。steam 解决。

新生代和老生代。

V8 的垃圾回收策略主要基于分代式垃圾回收机制。在 V8 中,主要将内存分为新生代和老生代。新生代的对象为存活时间较短的对象,老生代的对象为存活时间较长或常驻内存的对象。新生代空间中垃圾回收过程中幸存下来的对象会被提升到老生代空间。

新生代空间&Scavenge算法

Scavenge算法:将堆内存一分为from 和to空间,当我们分配对象时,先是在 From 空间中进行分配。当开始进行垃圾回收时,会检查 From 空间的存活对象,这些存活对象将被复制到 To 空间中,而非存活对象占用的空间将被释放。 完成复制后,From 空间和 To 空间的角色发生对换。

  • Scavenge 的缺点是只能使用堆内存中的一半
  • Scavenge 是典型的牺牲空间换取时间的算法,适合应用于新生代中,因为新生代中对象的生命周期较短
  • 当一个对象经过多次复制仍然存活时,它将会被认为是生命周期较长的对象,其随后会被移动到老生代中,这一过程称为晋升

老生代空间&标记清楚(Mark-Sweep)和标记整理(Mark-Compact)算法以及增量标记(incremental marking)技术

Mark-Sweep & Mark-Compact

  • Mark-Sweep:标记清除,其分为标记和清除两个阶段。在标记阶段遍历堆中的所有对象,并标记活着的对象,在清除阶段只清除没有被标记的对象。

Mark-Sweep 最大的问题在于进行一次标记清除回收后,内存空间会出现不连续的状态,内存碎片会对后续的内存分配造成问题,比如碎片空间不足以分配一个大对象导致提前触发垃圾回收。

  • 于是就有了 Mark-Compact:标记整理,简单来说就是标记完成后加一个整理阶段,存活对象往一端移动(合并),整理完成后直接清理掉边界外的内存。

Incremental Marking

为了避免出现 JavaScript 应用逻辑与垃圾回收器看到的不一致的情况,垃圾回收的 3 种基本算法需要将应用逻辑暂停下来, 待执行玩垃圾回收后再恢复执行应用逻辑,这种行为被称为全停顿(stop-the-world)。

对于新生代来说,全停顿的影响不大,但是对于老生代就需要改善。

为了降低全堆垃圾回收带来的停顿时间,V8 采用了增量标记(incremental marking)的技术, 大概是将原本一口气停顿完成的动作拆分为许多小“步进”, 每做完一“步进”就让 JavaScript 应用逻辑执行一小会儿,垃圾回收与应用逻辑交替执行直到标记阶段完成。

V8 后续还引入了延迟清理(lazy sweeping)、增量式整理(incremental compaction)、并发标记 等技术,感兴趣的可以自行了解。

内存泄漏

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

全局变量

未声明的变量或挂在全局 global 下的变量不会自动回收,将会常驻内存直到进程退出才会被释放,除非通过 delete 或 重新赋值为 undefined/null 解决之间的引用关系,才会被回收。

闭包

闭包会引用父级函数中的变量,如果闭包得不到释放,闭包引用的父级变量也不会释放从而导致内存泄漏。
闭包:外部作用域访问内部作用域内的变量即构成闭包,常见形式外部函数返回内部函数,内部函数返回了外部函数作用域的变量。闭包会形成独立作用域。

慎将内存做为缓存

模块私有变量内存永驻

在加载一个模块代码之前,Node.js 会使用一个如下的函数封装器将其封装,保证了顶层的变量(var、const、let)在模块范围内,而不是全局对象。

这个时候就会形成一个闭包,在 require 时会被加载一次,将 exports 对象保存于内存中,直到进程退出才会回收,这个将会导致的是内存常驻,所以避免一些没必要的模块加载,否则也会造成内存增加。

(function(exports, require, module, __filename, __dirname) {
    // 模块的代码实际上在这里
});

事件重复监听

其它注意事项

在使用定时器 setInterval 时记的使用对应的 clearInterval 进行清除,因为 setInterval 执行完之后会返回一个值且不会自动释放。

内存泄露的检测(memwatch & heapdump)

memwatch

  • 监听leak 事件, 打印信息。
  • memwatch 判定内存泄漏事件发生的规则如下:当你的堆内存在5个连续的垃圾回收周期内保持持续增长,那么一个内存泄漏事件被派发。

heapdump
它可以使用来将v8引擎的堆内存内容dump出来(可以在指定文件路径下生成.heapsnapshot的文件),这样你就可以在Chrome的开发者工具中查看问题。

如何自己检查NodeJS的代码是否存在内存泄漏

node 事件循环

  • timers:执行setTimeout() 和 setInterval()中到期的callback。
  • I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的这一阶段执行
  • idle, prepare:仅内部使用
  • poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段
  • check:执行setImmediate的callback
  • close callbacks:执行close事件的callback,例如socket.on(“close”,func)

优先级

观察者分为idea观察者、io观察者、check观察者,优先级:idle > io > check。

  • process.nextTick属于idea观察者,它是在本轮循环执行的,而且是所有异步任务里面最快执行的。Node 执行完所有同步任务,接下来就会执行。
  • setTimeout属于io观察者。
  • setimediate属于check观察者, 异步不接时间参数。
  • promise.then属于微任务,微任务队列追加在 process.nextTick 队列的后面,也
    属于本轮循环。

优先级:同步任务 > process.nextTick > promise.then > setTimeout > setimediate。观察者分为idea观察者、io观察者、check观察者,优先级:idle > io > check。

promise 中resolve和reject同级别的console.log 属于同步, 优先级等于同步任务。

Node.js 的构成

  • Node Standard Library:Node.js 标准库,对外提供的 JavaScript 接口,例如模块 http、buffer、fs、stream 等

  • Node bindings:这里就是 JavaScript 与 C++ 连接的桥梁,对下层模块进行封装,向上层提供基础的 API 接口。

  • V8:Google 开源的高性能 JavaScript 引擎,使用 C++ 开发,并且应用于谷歌浏览器。如果您感兴趣想学习更多的 V8 引擎知识,请访问 What is V8?

  • Libuv:是一个跨平台的支持事件驱动的 I/O 库。它是使用 C 和 C++ 语言为 Node.js 所开发的,同时也是 I/O 操作的核心部分,例如读取文件和 OS 交互。来自一份 Libuv 的中文教程

  • C-ares:C-ares 是一个异步 DNS 解析库

  • Low-Level Components:提供了 http 解析、OpenSSL、数据压缩(zlib)等功能。

node 性能优化

  1. 使用最新版本nodejs
  • V8版本更新
  • Node.js 内部代码的更新优化。
  1. Promise.all()与 Promise.race()

  2. 优化 V8 GC
    坑一:使用大对象作为缓存,导致老生代(Old Space)的垃圾回收变慢, 使用redis代替
    坑二:新生代空间不足,导致频繁 GC
    64(默认) 128

  3. 避免使用同步IO

  4. 不要让静态资源使用Node.js
    cdn 存储静态资源,实现动静分离

  5. 在客户端渲染
    前后端分离

  6. 使用gzip
    node后端使用compress 中间件

  7. Session自由化

node 常用框架

koa2

express

egg

nest

整理中,未完待续…

最后

以上就是会撒娇鸵鸟为你收集整理的nodejs整理js基础node的全部内容,希望文章能够帮你解决nodejs整理js基础node所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部