广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Node.js中模块加载机制的原理是什么
  • 577
分享到

Node.js中模块加载机制的原理是什么

2024-04-02 19:04:59 577人浏览 安东尼
摘要

这期内容当中小编将会给大家带来有关node.js中模块加载机制的原理是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。简单例子老规矩,讲原理前我们先来一个简单的例子,从

这期内容当中小编将会给大家带来有关node.js中模块加载机制的原理是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

简单例子

老规矩,讲原理前我们先来一个简单的例子,从这个例子入手一步一步深入原理。node.js里面如果要导出某个内容,需要使用module.exports,使用module.exports几乎可以导出任意类型的JS对象,包括字符串,函数,对象,数组等等。我们先来建一个a.js导出一个最简单的hello world:

// a.js   module.exports = "hello world";

然后再来一个b.js导出一个函数:

// b.js  function add(a, b) {    return a + b;  }  module.exports = add;

然后在index.js里面使用他们,即require他们,require函数返回的结果就是对应文件module.exports的值:

// index.js  const a = require('./a.js');  const add = require('./b.js'); console.log(a);      // "hello world"  console.log(add(1, 2));    // b导出的是一个加法函数,可以直接使用,这行结果是3

require会先运行目标文件

当我们require某个模块时,并不是只拿他的module.exports,而是会从头开始运行这个文件,module.exports = XXX其实也只是其中一行代码,我们后面会讲到,这行代码的效果其实就是修改模块里面的exports属性。比如我们再来一个c.js:

// c.js  let c = 1; cc = c + 1;  module.exports = c;  c = 6;

在c.js里面我们导出了一个c,这个c经过了几步计算,当运行到module.exports = c;这行时c的值为2,所以我们require的c.js的值就是2,后面将c的值改为了6并不影响前面的这行代码:

const c = require('./c.js');  console.log(c);  // c的值是2

前面c.js的变量c是一个基本数据类型,所以后面的c = 6;不影响前面的module.exports,那他如果是一个引用类型呢?我们直接来试试吧:

// d.js  let d = {    num: 1  };  d.num++;  module.exports = d; d.num = 6;

然后在index.js里面require他:

const d = require('./d.js');  console.log(d);     // { num: 6 }

我们发现在module.exports后面给d.num赋值仍然生效了,因为d是一个对象,是一个引用类型,我们可以通过这个引用来修改他的值。其实对于引用类型来说,不仅仅在module.exports后面可以修改他的值,在模块外面也可以修改,比如index.js里面就可以直接改:

const d = require('./d.js');  d.num = 7;  console.log(d);     // { num: 7 }

require和module.exports不是黑魔法

我们通过前面的例子可以看出来,require和module.exports干的事情并不复杂,我们先假设有一个全局对象{},初始情况下是空的,当你require某个文件时,就将这个文件拿出来执行,如果这个文件里面存在module.exports,当运行到这行代码时将module.exports的值加入这个对象,键为对应的文件名,最终这个对象就长这样:

{    "a.js": "hello world",    "b.js": function add(){},    "c.js": 2,    "d.js": { num: 2 }  }

当你再次require某个文件时,如果这个对象里面有对应的值,就直接返回给你,如果没有就重复前面的步骤,执行目标文件,然后将它的module.exports加入这个全局对象,并返回给调用者。这个全局对象其实就是我们经常听说的缓存。所以require和module.exports并没有什么黑魔法,就只是运行并获取目标文件的值,然后加入缓存,用的时候拿出来用就行。再看看这个对象,因为d.js是一个引用类型,所以你在任何地方获取了这个引用都可以更改他的值,如果不希望自己模块的值被更改,需要自己写模块时进行处理,比如使用Object.freeze(),Object.defineProperty()之类的方法。

模块类型和加载顺序

这一节的内容都是一些概念,比较枯燥,但是也是我们需要了解的。

模块类型

Node.js的模块有好几种类型,前面我们使用的其实都是文件模块,总结下来,主要有这两种类型:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   内置模块:就是Node.js原生提供的功能,比如fs,Http等等,这些模块在Node.js进程起来时就加载了。

  3.   文件模块:我们前面写的几个模块,还有第三方模块,即node_modules下面的模块都是文件模块。

加载顺序

加载顺序是指当我们require(X)时,应该按照什么顺序去哪里找X,在官方文档上有详细伪代码,总结下来大概是这么个顺序:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   优先加载内置模块,即使有同名文件,也会优先使用内置模块。

  3.   不是内置模块,先去缓存找。

  4.   缓存没有就去找对应路径的文件。

  5.   不存在对应的文件,就将这个路径作为文件夹加载。

  6.   对应的文件和文件夹都找不到就去node_modules下面找。

  7.   还找不到就报错了。

加载文件夹

前面提到找不到文件就找文件夹,但是不可能将整个文件夹都加载进来,加载文件夹的时候也是有一个加载顺序的:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   先看看这个文件夹下面有没有package.JSON,如果有就找里面的main字段,main字段有值就加载对应的文件。所以如果大家在看一些第三方库源码时找不到入口就看看他package.json里面的main字段吧,比如Jquery的main字段就是这样:"main": "dist/jquery.js"。

     2.  如果没有package.json或者package.json里面没有main就找index文件。

     3.   如果这两步都找不到就报错了。

支持的文件类型

require主要支持三种文件类型:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   .js:.js文件是我们最常用的文件类型,加载的时候会先运行整个JS文件,然后将前面说的module.exports作为require的返回值。

  3.   .json:.json文件是一个普通的文本文件,直接用JSON.parse将其转化为对象返回就行。

  4.   .node:.node文件是c++编译后的二进制文件,纯前端一般很少接触这个类型。

手写require

前面其实我们已经将原理讲的七七八八了,下面来到我们的重头戏,自己实现一个require。实现require其实就是实现整个Node.js的模块加载机制,我们再来理一下需要解决的问题:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   通过传入的路径名找到对应的文件。

  3.   执行找到的文件,同时要注入module和require这些方法和属性,以便模块文件使用。

  4.   返回模块的module.exports

本文的手写代码全部参照Node.js官方源码,函数名和变量名尽量保持一致,其实就是精简版的源码,大家可以对照着看,写到具体方法时我也会贴上对应的源码地址。总体的代码都在这个文件里面:https://GitHub.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js

Module类

Node.js模块加载的功能全部在Module类里面,整个代码使用面向对象的思想,如果你对JS的面向对象还不是很熟悉可以先看看这篇文章。Module类的构造函数也不复杂,主要是一些值的初始化,为了跟官方Module名字区分开,我们自己的类命名为MyModule:

function MyModule(id = '') {    this.id = id;       // 这个id其实就是我们require的路径    this.path = path.dirname(id);     // path是Node.js内置模块,用它来获取传入参数对应的文件夹路径    this.exports = {};        // 导出的东西放这里,初始化为空对象    this.filename = null;     // 模块对应的文件名    this.loaded = false;      // loaded用来标识当前模块是否已经加载  }

require方法

我们一直用的require其实是Module类的一个实例方法,内容很简单,先做一些参数检查,然后调用Module._load方法,源码看这里:https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L970。精简版的代码如下:

MyModule.prototype.require = function (id) {    return Module._load(id);  }

MyModule._load

MyModule._load是一个静态方法,这才是require方法的真正主体,他干的事情其实是:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   先检查请求的模块在缓存中是否已经存在了,如果存在了直接返回缓存模块的exports。

  3.   如果不在缓存中,就new一个Module实例,用这个实例加载对应的模块,并返回模块的exports。

我们自己来实现下这两个需求,缓存直接放在Module._cache这个静态变量上,这个变量官方初始化使用的是Object.create(null),这样可以使创建出来的原型指向null,我们也这样做吧:

MyModule._cache = Object.create(null);  MyModule._load = function (request) {    // request是我们传入的路劲参数    const filename = MyModule._resolveFilename(request);    // 先检查缓存,如果缓存存在且已经加载,直接返回缓存    const cachedModule = MyModule._cache[filename];    if (cachedModule !== undefined) {      return cachedModule.exports;   }    // 如果缓存不存在,我们就加载这个模块    // 加载前先new一个MyModule实例,然后调用实例方法load来加载    // 加载完成直接返回module.exports    const module = new MyModule(filename);    // load之前就将这个模块缓存下来,这样如果有循环引用就会拿到这个缓存,但是这个缓存里面的exports可能还没有或者不完整    MyModule._cache[filename] = module;    module.load(filename);    return module.exports;  }

上述代码对应的源码看这里:https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L735

可以看到上述源码还调用了两个方法:MyModule._resolveFilename和MyModule.prototype.load,下面我们来实现下这两个方法。

MyModule._resolveFilename

MyModule._resolveFilename从名字就可以看出来,这个方法是通过用户传入的require参数来解析到真正的文件地址的,源码中这个方法比较复杂,因为按照前面讲的,他要支持多种参数:内置模块,相对路径,绝对路径,文件夹和第三方模块等等,如果是文件夹或者第三方模块还要解析里面的package.json和index.js。我们这里主要讲原理,所以我们就只实现通过相对路径和绝对路径来查找文件,并支持自动添加js和json两种后缀名:

MyModule._resolveFilename = function (request) {    const filename = path.resolve(request);   // 获取传入参数对应的绝对路径    const extname = path.extname(request);    // 获取文件后缀名   // 如果没有文件后缀名,尝试添加.js和.json    if (!extname) {      const exts = Object.keys(MyModule._extensions);      for (let i = 0; i < exts.length; i++) {        const currentPath = `${filename}${exts[i]}`;        // 如果拼接后的文件存在,返回拼接的路径        if (fs.existsSync(currentPath)) {          return currentPath;        }      }    }    return filename;  }

上述源码中我们还用到了一个静态变量MyModule._extensions,这个变量是用来存各种文件对应的处理方法的,我们后面会实现他。

MyModule._resolveFilename对应的源码看这里:https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L822

MyModule.prototype.load

MyModule.prototype.load是一个实例方法,这个方法就是真正用来加载模块的方法,这其实也是不同类型文件加载的一个入口,不同类型的文件会对应MyModule._extensions里面的一个方法:

MyModule.prototype.load = function (filename) {    // 获取文件后缀名    const extname = path.extname(filename);    // 调用后缀名对应的处理函数来处理    MyModule._extensions[extname](this, filename);    this.loaded = true;  }

注意这段代码里面的this指向的是module实例,因为他是一个实例方法。对应的源码看这里: https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L942

加载js文件: MyModule._extensions['.js']

前面我们说过不同文件类型的处理方法都挂载在MyModule._extensions上面的,我们先来实现.js类型文件的加载:

MyModule._extensions['.js'] = function (module, filename) {    const content = fs.readFileSync(filename, 'utf8');    module._compile(content, filename);  }

可以看到js的加载方法很简单,只是把文件内容读出来,然后调了另外一个实例方法_compile来执行他。对应的源码看这里:https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L1098

编译执行js文件:MyModule.prototype._compile

MyModule.prototype._compile是加载JS文件的核心所在,也是我们最常使用的方法,这个方法需要将目标文件拿出来执行一遍,执行之前需要将它整个代码包裹一层,以便注入exports, require, module, __dirname, __filename,这也是我们能在JS文件里面直接使用这几个变量的原因。要实现这种注入也不难,假如我们require的文件是一个简单的Hello World,长这样:

module.exports = "hello world";

那我们怎么来给他注入module这个变量呢?答案是执行的时候在他外面再加一层函数,使他变成这样:

function (module) { // 注入module变量,其实几个变量同理    module.exports = "hello world";  }

所以我们如果将文件内容作为一个字符串的话,为了让他能够变成上面这样,我们需要再给他拼接上开头和结尾,我们直接将开头和结尾放在一个数组里面:

MyModule.wrapper = [    '(function (exports, require, module, __filename, __dirname) { ',    '\n});'  ];

注意我们拼接的开头和结尾多了一个()包裹,这样我们后面可以拿到这个匿名函数,在后面再加一个()就可以传参数执行了。然后将需要执行的函数拼接到这个方法中间:

MyModule.wrap = function (script) {    return MyModule.wrapper[0] + script + MyModule.wrapper[1];  };

这样通过MyModule.wrap包装的代码就可以获取到exports, require, module, __filename, __dirname这几个变量了。知道了这些就可以来写MyModule.prototype._compile了:

MyModule.prototype._compile = function (content, filename) {    const wrapper = Module.wrap(content);    // 获取包装后函数体    // vm是nodejs的虚拟机沙盒模块,runInThisContext方法可以接受一个字符串并将它转化为一个函数    // 返回值就是转化后的函数,所以compiledWrapper是一个函数    const compiledWrapper = vm.runInThisContext(wrapper, {      filename,      lineOffset: 0,      displayErrors: true,    });    // 准备exports, require, module, __filename, __dirname这几个参数    // exports可以直接用module.exports,即this.exports    // require官方源码中还包装了一层,其实最后调用的还是this.require    // module不用说,就是this了    // __filename直接用传进来的filename参数了    // __dirname需要通过filename获取下    const dirname = path.dirname(filename);    compiledWrapper.call(this.exports, this.exports, this.require, this,      filename, dirname);  }

上述代码要注意我们注入进去的几个参数和通过call传进去的this:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   this:compiledWrapper是通过call调用的,第一个参数就是里面的this,这里我们传入的是this.exports,也就是module.exports,也就是说我们js文件里面this是对module.exports的一个引用。

  3.   exports: compiledWrapper正式接收的第一个参数是exports,我们传的也是this.exports,所以js文件里面的exports也是对module.exports的一个引用。

  4.   require: 这个方法我们传的是this.require,其实就是MyModule.prototype.require,也就是MyModule._load。

  5.   module: 我们传入的是this,也就是当前模块的实例。

  6.   __filename:文件所在的绝对路径。

  7.   __dirname: 文件所在文件夹的绝对路径。

到这里,我们的JS文件其实已经记载完了,对应的源码看这里:https://github.com/nodejs/node/blob/c6b96895cc74bc6bd658b4c6d5ea152d6e686d20/lib/internal/modules/cjs/loader.js#L1043

加载json文件: MyModule._extensions['.json']

加载json文件就简单多了,只需要将文件读出来解析成json就行了:

MyModule._extensions['.json'] = function (module, filename) {    const content = fs.readFileSync(filename, 'utf8');    module.exports = JSONParse(content);  }

exports和module.exports的区别

网上经常有人问,node.js里面的exports和module.exports到底有什么区别,其实前面我们的手写代码已经给出答案了,我们这里再就这个问题详细讲解下。exports和module.exports这两个变量都是通过下面这行代码注入的。

compiledWrapper.call(this.exports, this.exports, this.require, this,      filename, dirname);

初始状态下,exports === module.exports === {},exports是module.exports的一个引用,如果你一直是这样使用的:

exports.a = 1;  module.exports.b = 2; console.log(exports === module.exports);   // true

上述代码中,exports和module.exports都是指向同一个对象{},你往这个对象上添加属性并没有改变这个对象本身的引用地址,所以exports === module.exports一直成立。

但是如果你哪天这样使用了:

exports = {    a: 1  }

或者这样使用了:

module.exports = {      b: 2  }

那其实你是给exports或者module.exports重新赋值了,改变了他们的引用地址,那这两个属性的连接就断开了,他们就不再相等了。需要注意的是,你对module.exports的重新赋值会作为模块的导出内容,但是你对exports的重新赋值并不能改变模块导出内容,只是改变了exports这个变量而已,因为模块始终是module,导出内容是module.exports。

循环引用

Node.js对于循环引用是进行了处理的,下面是官方例子:

a.js:

console.log('a 开始');  exports.done = false;  const b = require('./b.js');  console.log('在 a 中,b.done = %j', b.done);  exports.done = true;  console.log('a 结束');

b.js:

console.log('b 开始');  exports.done = false;  const a = require('./a.js');  console.log('在 b 中,a.done = %j', a.done);  exports.done = true;  console.log('b 结束');

main.js:

console.log('main 开始');  const a = require('./a.js');  const b = require('./b.js');  console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);

当 main.js 加载 a.js 时, a.js 又加载 b.js。 此时, b.js 会尝试去加载 a.js。 为了防止无限的循环,会返回一个 a.js 的 exports 对象的 未完成的副本 给 b.js 模块。 然后 b.js 完成加载,并将 exports 对象提供给 a.js 模块。

那么这个效果是怎么实现的呢?答案就在我们的MyModule._load源码里面,注意这两行代码的顺序:

MyModule._cache[filename] = module;  module.load(filename);

上述代码中我们是先将缓存设置了,然后再执行的真正的load,顺着这个思路我能来理一下这里的加载流程:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.   main加载a,a在真正加载前先去缓存中占一个位置

  3.   a在正式加载时加载了b

  4.   b又去加载了a,这时候缓存中已经有a了,所以直接返回a.exports,即使这时候的exports是不完整的。

总结

  1.  require不是黑魔法,整个Node.js的模块加载机制都是JS实现的。

  2.  每个模块里面的exports, require, module, __filename, __dirname五个参数都不是全局变量,而是模块加载的时候注入的。

  3.  为了注入这几个变量,我们需要将用户的代码用一个函数包裹起来,拼一个字符串然后调用沙盒模块vm来实现。

  4.  初始状态下,模块里面的this, exports, module.exports都指向同一个对象,如果你对他们重新赋值,这种连接就断了。

  5.  对module.exports的重新赋值会作为模块的导出内容,但是你对exports的重新赋值并不能改变模块导出内容,只是改变了exports这个变量而已,因为模块始终是module,导出内容是module.exports。

    6.  为了解决循环引用,模块在加载前就会被加入缓存,下次再加载会直接返回缓存,如果这时候模块还没加载完,你可能拿到未完成的exports。

    7.  Node.js实现的这套加载机制叫CommonJS。

上述就是小编为大家分享的Node.js中模块加载机制的原理是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网JavaScript频道。

--结束END--

本文标题: Node.js中模块加载机制的原理是什么

本文链接: https://www.lsjlt.com/news/74202.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Node.js中模块加载机制的原理是什么
    这期内容当中小编将会给大家带来有关Node.js中模块加载机制的原理是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。简单例子老规矩,讲原理前我们先来一个简单的例子,从...
    99+
    2022-10-19
  • Node.js模块的加载逻辑是什么
    这篇文章主要介绍Node.js模块的加载逻辑是什么,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、按照组织方式划分模块文件模块:是我们上一章节说过的,就是一个独立的.js文件。目录模块:是我们可以将多个独立的.js...
    99+
    2023-06-26
  • Node.js中Nestjs框架的模块机制是什么
    这篇文章主要介绍“Node.js中Nestjs框架的模块机制是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Node.js中Nestjs框架的模块机制是什么”文...
    99+
    2022-10-19
  • Node.js源码中cjs模块的加载过程是什么
    这篇文章主要介绍了Node.js源码中cjs模块的加载过程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Node.js源码中cjs模块的加载过程是什么文章都会有所收获,下...
    99+
    2022-10-19
  • JVM加载class文件的原理机制是什么
    今天小编给大家分享一下JVM加载class文件的原理机制是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、JVM简介J...
    99+
    2023-06-30
  • Node.js中Require机制的原理是什么
    这篇文章给大家介绍Node.js中Require机制的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。什么是 CommonJS每一个文件就是一个模块,拥有自己独立的作用域,变量...
    99+
    2022-10-19
  • Java中类加载机制及热部署的原理是什么
    这篇文章主要介绍了Java中类加载机制及热部署的原理是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、什么是类加载类的加载指的是将类的.class文件的二进制数据读入到...
    99+
    2023-06-15
  • Node.js内置模块的运行机制是什么
    今天小编给大家分享一下Node.js内置模块的运行机制是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。内置模块一些栗子F...
    99+
    2023-07-04
  • 简单模拟node.js中require的加载机制
    一、先了解一下,nodejs中require的加载机制 1、require的加载文件顺序 require 加载文件时可以省略扩展名: require('./module'); ...
    99+
    2022-06-04
    加载 机制 简单
  • JVM类加载机制过程以及原理是什么
    这篇文章主要介绍“JVM类加载机制过程以及原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JVM类加载机制过程以及原理是什么”文章能帮助大家解决问题。一、做一个小测试通过注释,标注出下面两个...
    99+
    2023-07-05
  • Node.js的模块化机制和Buffer对象是什么
    本篇内容主要讲解“Node.js的模块化机制和Buffer对象是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Node.js的模块化机制和Buffer对象是什么”吧!一、Node.js的模块...
    99+
    2023-06-29
  • Node的模块机制是什么
    这篇文章主要介绍“Node的模块机制是什么”,在日常操作中,相信很多人在Node的模块机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node的模块机制是什么”的疑惑...
    99+
    2022-10-19
  • es6模块的原理是什么
    这篇文章主要讲解了“es6模块的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“es6模块的原理是什么”吧!ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及...
    99+
    2023-07-04
  • node.js中事件轮询机制的原理是什么
    node.js中事件轮询机制的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。借助libuv库实现的概括事件轮询机制:分为六个阶段...
    99+
    2022-10-19
  • PostgreSQL中空闲数据块管理机制的原理是什么
    本篇文章给大家分享的是有关PostgreSQL中空闲数据块管理机制的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。数据块空闲空间的产...
    99+
    2022-10-18
  • webpack模块化的原理是什么
    本篇内容介绍了“webpack模块化的原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!commonjs在webpack中既可以书写c...
    99+
    2023-07-05
  • node中的模块系统原理是什么
    本篇内容介绍了“node中的模块系统原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!模块系统并不是所有编程语言都有内置的模块系统,J...
    99+
    2023-07-05
  • Node.js模块查找,引用及缓存机制是什么
    这篇文章主要介绍“Node.js模块查找,引用及缓存机制是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Node.js模块查找,引用及缓存机制是什么”文章能帮助大家解决问题。1. Node.js...
    99+
    2023-07-05
  • Java类的加载机制是什么
    这篇文章主要讲解了“Java类的加载机制是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java类的加载机制是什么”吧!1、什么是类的加载类的加载指的是将类的.class文件中的二进制数...
    99+
    2023-06-17
  • ubuntu禁止模块加载的方法是什么
    这篇文章主要介绍“ubuntu禁止模块加载的方法是什么”,在日常操作中,相信很多人在ubuntu禁止模块加载的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ubuntu禁止模块加载的方法是什么”的疑...
    99+
    2023-07-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作