本文介绍: 因为所有的NodeJS文件执行时候都会被包裹到一个函数中,this都被修改module.exports。(详细请看之前的Node模块原理分析【详细】那篇文章)。和浏览器中一样NodeJS中也有事件循环(Event Loop),但是由于代码执行的宿主环境应用场景不同,所以两者的事件循环也有所不同扩展阅读:在NodeJS中使用libuv实现了Event Loop源码地址https://github.com/libuv/libuv什么是包?

1、NodeJS中的this为什么一个对象

因为所有的NodeJS文件执行时候都会被包裹到一个函数中,this都被修改module.exports。(详细请看之前的Node模块原理分析【详细】那篇文章)。
在这里插入图片描述
在这里插入图片描述

2、NodeJS中为什么可以直接使用exportsrequiremodule__filename__dirname?

因为所有的NodeJS文件执行时候都会被包裹到一个函数中,这些属性都被通过参数的形式传递过来了。
// var args = [this.exports, require, module, filename, dirname];
// var result = compiledWrapper.call(this.exports, args);
都会被包裹到下面函数中:

(function (exports, require, module, __filename, __dirname) {
exports.名 = 值;
});

3、NodeJS中为什么不能直接exports赋值,而可以module.exports赋值

<!--
(function (exports, require, module, __filename, __dirname) {
    exports = "lnj";
});
jsScript.call(module.exports, module.exports);
return module.exports;

相当于
let exports = module.exports;
exports = "lnj";
return module.exports;

在这里插入图片描述
exports是形参module.exports传递给它,两者指向同一个对象。如果直接给exports赋值(exports=‘aaa’)则相当于修改了它的指向,但最后返回module.exports。
在这里插入图片描述
在这里插入图片描述

4、通过require导入包的时候应该使用var/let还是const

导入包的目的是使用包而不是修改包,所以导入包时使用const接受。

5、requireimport区别

importrequire都是被模块化所使用。在ES6当中,用export导出接口,用import引入模块。但是node模块中,使用module.exports/exports导出接口,使用require引入模块,

  1. 区别一:出现的时间不同
  2. 遵循的模块化规范不同
  3. 本质

6、浏览器事件循环

6.1、JS是单线程

JS中的代码都是串行的,前面没有执行完毕后面不能执行。

6.2、执行顺序

  1. 程序运行会从上至下依次执行所有的同步代码
  2. 在执行的过程中如果遇到异步代码会将异步代码放到事件循环中。
  3. 当所有同步代码都执行完毕后,JS会不断检测事件循环中的异步代码是否满足条件
  4. 一旦满足条件就执行满足条件的异步代码

6.3、宏任务和微任务

在JS的异步代码中又区分“宏任务(MacroTask)”和“微任务(MicroTask)”。

任务:宏/大的意思,可以理解比较费时比较慢的任务
任务:微/小的意思,可以理解相对没那么费时没那么慢的任务

6.4、常见的宏任务和微任务

宏任务setTimeoutsetIntervalsetImmediate(IE独有)…
微任务:Promise、MutationObserverprocess.nextTick(node独有)…

注意点:所有的宏任务和微任务都会放到自己的执行队列中,也就是有一个宏任务队列和一个微任务队列。所有放到列中的任务都采用“先进先出原则”,也就是多个任务同时满足条件,那么会先执行先放进去的

6.5、完整执行顺序

在这里插入图片描述
在这里插入图片描述

  1. 从上至下执行所有同步代码。
  2. 执行微任务队列中的所有代码。
  3. 执行宏任务中满足条件代码。
  4. 执行微任务队列中所有代码。
  5. 执行宏任务中满足条件代码。
    … …

每次执行完一个宏任务都会立刻检查微任务队列有没有被清空,如果没有就立刻清空

附:
1、setImmediate(IE浏览器独有)在这里插入图片描述
2、MutationObserver是专门监听节点的变化
在这里插入图片描述

// html
<body&gt;
<div&gt;</div>
<button class="add">添加节点</button>
<button class="del">删除节点</button>
</body>

// js
let oDiv = document.querySelector("div");
    let oAddBtn = document.querySelector(".add");
    let oDelBtn = document.querySelector(".del");
    oAddBtn.onclick = function () {
        let op = document.createElement("p");
        op.innerText = "我是段落";
        oDiv.appendChild(op);
    }
    oDelBtn.onclick = function () {
        let op = document.querySelector("p");
        oDiv.removeChild(op);
    }
    let mb = new MutationObserver(function () {
        console.log("执行了");
    });
    mb.observe(oDiv, {
        "childList": true
    });
    console.log("同步代码Start");
    console.log("同步代码End");

在这里插入图片描述

7、NodeJS的事件循环(Event Loop)

7.1、概述

浏览器中一样NodeJS中也有事件循环(Event Loop),但是由于代码执行的宿主环境应用场景不同,所以两者的事件循环也有所不同。

扩展阅读
在NodeJS中使用libuv实现了Event Loop
源码地址https://github.com/libuv/libuv

7.2、NodeJS事件循环和浏览器事件循环区别

在这里插入图片描述

  1. 任务队列个数不同。
  2. 微任务队列不同。
    • 浏览器事件循环中有专门存储微任务的队列。
    • NodeJS事件循环中没有专门存储微任务的队列。
  3. 微任务执行时机不同。
  4. 微任务优先级不同
    • 浏览器事件循环中如果多个微任务同时满足执行条件,采用先进先出。
    • NodeJS事件循环中如果多个微任务同时满足执行条件,会按照优先级执行。

7.3、NodeJS中的任务队列

图一:
在这里插入图片描述

  1. 注意点:

浏览器不同的是没有宏任务队列和微任务队列的概念
宏任务被放到了不同的队列中,但是没有队列是存放微任务的队列。
微任务会在执行完同步代码和队列切换的时候执行。

什么时候切换队列?
当队列为空(已经执行完毕或者没有满足条件回倒)或者执行的回调函数数量达到系统设定的阈值时任务队列就会切换

  1. 注意点:
    在NodeJS中process.nextTick微任务的优先级高于Promise.resolve微任务。

图二:NodeJS完整执行顺序
在这里插入图片描述
注意点:
执行完poll,会查看check队列是否内容,有就切换check。如果check队列没有内容,就会查看timers是否内容,有就切换到timers。如果check队列和timers队列都没有内容,为了避免资源浪费就会阻塞在poll。

7.4、NodeJS-EventLoop面试题

/*
注意点: 如下代码输出结果随机的
        在NodeJS中指定延迟时间是有一定的误差的, 所以导致了输出结果随机问题
* */
/*
setTimeout(function () {
    console.log("setTimeout");
}, 0);
setImmediate(function () {
    console.log("setImmediate");
});
 */

// 但是在下面的代码中输出结果都是固定的,即无论setTimeout、setImmediate顺序怎样,都会先执行setImmediate代码。
const path = require("path");
const fs = require("fs");

fs.readFile(path.join(__dirname, "04.js"), function () {
    setTimeout(function () {
        console.log("setTimeout");
    }, 0);
    setImmediate(function () {
        console.log("setImmediate");
    });
});

原因
在这里插入图片描述

8、自定义本地包和全局

  1. 什么是包?
    包就是一个文件夹用来管理模块和模块之间的各种关系

  2. 包使用
    npm install xxx 安装包
    const xxx = require(xxx); 使用包

8.1、包的规范(了解)

8.2、package.json字段分析(了解)

8.3、自定义实现步骤

  1. 创建一个包文件夹
  2. 初始化一个package.json文件。
  3. 初始化一个包入口js文件。
    注意点:如果没有配置main,默认会将index.js作为入口,如果包中没有index.js,那么就必须配置main。
  4. 根据包信息配置package.json文件。
    注意点:通过scripts可以帮助我们记住指令,然后通过npm run xxx方式,就可以执行该指令。如果指令的名称叫做start或者test,那么执行的时候可以不加run

全局包:一般全局包都是些工具包比如nrmyarncnpm等,工具包的特点需要自定义指令。

  1. package.json添加bin属性,告诉系统执行全局命令式需要执行哪一。个JS文件。
  2. 全局命令执行的JS文件中添加#! /usr/bin/envnode。 (node环境执行)
  3. 通过npm link本地放到全局方便我们调试

在这里插入图片描述

在这里插入图片描述
npm link
在这里插入图片描述

8.4、自定义发布官网

  1. https://www.npmjs.com注册账号
  2. 先切换到包所在目录下,比如:06node_moduleslgg
  3. 终端输入npm addUser。
  4. 终端输入npm publish

注意:在第三步前,要把源切换为官网。
nrm ls;
nrm use npm;

原文地址:https://blog.csdn.net/weixin_44767973/article/details/127705276

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_33694.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注