Node.js入门笔记(1):Module 模块化(require用法)

151 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情 前言

不像其他的编程语言,JavaScript对在开发中对模块规范的比较深入,目前流行的JavaScript模块规范有两种,分别是CommonJS和AMD,CommonJS将每个文件都看作一个模块,模块内部定义的变量都是私有的,无法被其他模块使用,除非使用预定义的方法将内部的变量暴露出来(通过exports和require关键字来实现),node.js就是以CommonJS规范来进行开发的。

node.js中模块有两种类型:核心模块和文件模块,核心模块直接使用名称获取,比如最常用的http模块

var http=require('http');

本文笔者将为大家介绍另一种:

1.require关键字的使用

const Test = {
    talk:function(){
        console.log(222)
    }
}
module.exports = Test

通过module.exports向外输出一个自定义模块,该模块提供了一个接口(Test),然后使用module.exports将该接口暴露给外部使用,

接口已经暴露出来,接下来就是如何使用接口暴露的函数,我们可以通过在另外一个js文件中通过require进行引入

在通过相对路径进行引入模块的时候,不要省略“./”。

const t1 = require("./test1")
console.log(t1.talk) //222

这样我们就实现了在一个js中声明模块并暴露接口,并且在另一个js中引入并执行接口中的方法。

let talk = require("./test1").talk
talk()//222

如果我们只是想简单的使用模块中的一个方法,可以通过以上的方式进行简写

2.require的运行机制

2.1 重复加载 一个模块在node中被执行后会被缓存起来,加载的时候会生成一个副本,遇到重复加载的时候会直接使用缓存中的副本进行加载,不会进行重复的加载,每个模块在缓存中只有一个实例

require加载模块是同步而不是异步的,一方面是遵循了CommonJS的标准,另一方面,笔者认为,如果是一个公共依赖模块,那应该是按照同步的执行才对,这样才能在后续代码中能够正确的访问到模块中的方法。

并且我们也可以反证:为什么不是异步?因为异步本身解决的问题是加载JS消耗太长造成后续代码阻塞,但由于缓存加载的策略,node会自动缓存已经加载的模块,并且访问的都是本地文件,所以IO消耗可以忽略,并且node一般作为服务来使用,频繁重启的可能性较少。

2.2缓存策略

Node会自动缓存经过require引入的文件,下次再引入而是直接从缓存中读取。但是即使有两个完全相同的文件,位于不同的路径下,则会存在俩种缓存。例如我们可以用下面的代码查看目前在缓存中的文件:

const t1 = require("./test1")
console.log(require.cache)

image.png 从上面我们可以看在缓存中的信息

2.3 require的隐患

加载一个模块时可能会带来隐藏的bug,比如以下栗子:

function test(){
    setInterval(() => {
        console.log('22222')
    }, 1000);
}
test()

module.exports = test
let talk = require("./test1")

我们在一个js中引入一个test1的模块,并没有执行其他操作,但是当前进程其实已经执行结束的时候却还有定时器在执行,所以当我们在生成环境中引入模块的时候要注意保持警惕,以防内存泄漏的问题。