跳到主要内容

谈谈浏览器和nodejs环境区别

  • nodejs环境上多了模块化
  • 浏览器中的闭包、事件循环、作用域的区别?

模块化​

  • 在Node.js环境中,可以使用CommonJS或ES模块系统进行模块化
  • 在nodejs中,每个文件都被视为一个模块

闭包​

  • 在Node.js环境中,闭包通常用于创建私有变量或实现模块化。
  • 函数内部使用了外部的变量就会产生闭包
  • 闭包产生的本质就是,当前环境中存在指向父级作用域的引用
  • 在nodejs中,模块作用域中,如果一个函数引用了外部变量,那么这个函数就形成了一个闭包
    • 因为它封装了对外部变量的访问,使得这个变量即使在函数执行完毕后,仍然不会被垃圾回收机制回收
  • 在nodejs中,模块作用域可以形成闭包,使得函数可以访问模块内部的变量
    • 在nodejs中,定义的变量,是模块私有变量
js
// nodejs的环境下产生了闭包, 浏览器中没有产生闭包
var i = 1; // nodejs中,定义了模块私有变量,在浏览器中,是全局变量
function a() {
console.log(i);
}
a();

作用域​

  • 在nodejs中,不仅有全局作用域,还有模块作用域

    • 每个nodejs文件都是一个模块,都有自己的作用域,也就是模块作用域
    • 在node.js中,每个模块都有自己的作用域,不会将变量泄漏到全局作用域
  • 作用域链:

    • 在nodejs中,作用域链的顺序是:局部作用域 -> 模块作用域 -> 全局作用域

    • 在浏览器中,作用域链的顺序是:局部作用域 -> 全局作用域。

  • 在浏览器环境中,全局作用域通常是window对象,而在Node.js环境中,则是global对象

  • var指向、this指向的作用域的也会有区别

  • 在nodejs中,module.exports、exports、this 指向同一个对象

var指向问题

  • nodejs中,使用 var 在全局作用域中声明的变量不会成为全局对象的属性
  • 浏览器中,浏览器中,var在全局范围内声明,则会成为全局作用域的变量,会绑定到window全局作用域中
js
// nodejs环境
var name = 'nodejs' // nodejs中,使用 var 关键字在全局作用域中声明的变量不会成为全局对象的属性
console.log(this.name) // undefined

// 浏览器环境
var name = 'nodejs' // 浏览器中,var在全局范围内声明,则会成为全局作用域的变量,会绑定到window全局作用域中
console.log(this.name) // nodejs

this指向问题

  • nodejs中,this 在全局作用域中不再指向全局对象,而是指向当前模块的 exports 对象(如果你没有导出任何内容,那么它就是一个空对象)

    • 在模块中,export、module.exports、this会共同指向一个对象
  • 浏览器中,this的指向会有几种情况,会根据指向根据环境不同而发生改变,

    • 比如
      • 作为对象方法调用
        • this会指向调用它的对象
      • 作为函数调用
        • this会指向全局对象
      • 作为构造函数调用
        • this是指向当前new出来的对象,也就是对象实例
      • 作为apply/call调用
        • this会指向传入的对象
      • 作为绑定事件事件调用
        • this 指向触发事件的DOM元素。

事件循环​

  • 事件循环是一种机制,解决异步非阻塞的问题, 通过事件循环去实现异步过程,能够确保单线程环境能够执行多个任务

  • 浏览器中,事件循环是 浏览器渲染主线程的工作方式,事件循环会开始一个循环,每次循环都会读取消息队列(任务队列)中的第一个任务执行

    • 浏览器是多个多进程多线程的程序,事件循环是发生在渲染进程这个阶段的
    • 渲染进程是浏览器中最繁忙的进程,每个进程都会默认开启一个主线程来执行具体的任务,渲染进程也会开启一个渲染主线程负责页面的渲染执行具体的任务
  • Node.js中的事件循环基于Libuv库,主要是处理io操作、定时器操作,通过异步非阻塞可以处理大量的io操作,提供系统的并发性能,同样也是浏览器的事件循环一样,会开始一个循环,每次循环会读取消息队列(任务队列)中的第一个任务执行

    libuv是一个跨平台异步IO的库,Libuv库提供了事件循环、线程池、异步I/O等功能

nodejs的事件循环3个重要阶段部分,Timers、Poll、Check

这三个阶段的组合使得Node.js能够高效地处理异步任务,同时保证了I/O操作的非阻塞执行

  • Timers(定时器):这个阶段处理通过setTimeout()和setInterval()设定的定时任务。在每次循环中,Node.js会检查是否有定时器到期,如果有,会将定时器的回调函数放入队列中等待执行。如果一个定时器设定的时间尚未到,它不会被执行。
  • Poll(轮询):这个阶段是Node.js处理I/O操作的核心部分。在这个阶段,Node.js会检索新的I/O事件,比如从文件系统中读取文件或者从网络中接收数据。当没有新的事件时,Node.js会等待事件的到来。当有事件触发时,它会执行回调函数,并且如果有设置了定时器,也会检查定时器是否到期。
  • Check(检查):在这个阶段,setImmediate()设定的回调函数会被执行。这个阶段的执行在Poll阶段之后,保证了在执行完I/O事件后立即执行这些回调函数