Node.js 基础 – 小七不懂前端 您所在的位置:网站首页 前端基本标签 Node.js 基础 – 小七不懂前端

Node.js 基础 – 小七不懂前端

2023-02-27 12:53| 来源: 网络整理| 查看: 265

nodejs介绍

🎉 官网地址

运行环境 为什么js可以在浏览器中被执行 因为被以下解析引擎所解析 Chrome =》 chrome v8 (最主流,性能最好) fire fox => odinmonkey 奥丁候 safari =》 jsCore ie => chakra 查克拉 为什么js可以解析BOM和DOM 浏览器内置API (DOM BOM XHR), js进行调用 代码运行的必要条件 Chrome运行环境 V8引擎环境 + 内置API (fs,http,path) JS调用内置API给到引擎去解析运行 js也可以用于后端开发 环境 node + node内置api node.js 是一个基于chromeV8的js运行环境 js跑在浏览器上,就是前端 / 跑在node上,就是后端(通俗一点) 为啥用v8 主流性能好。 所以,js在v8上,放到浏览器中,跑前端,放在node中,跑后端 新手常见误区,nodejs无法调用浏览器内置API(BOM DOM等,压根没有window对象) node能做啥 读写数据库,创建接口服务,构建web应用等等 node 三大特点(面试) 单线程、非阻塞I/O,事件驱动 前言:两个故事 为了更好地理解Node.js的三大特点,先给大家讲一大一小两个餐馆的故事。

高级餐厅(传统的服务器语言) 我们到一个比较高级的餐厅吃饭,服务员是一对一服务(每个用户都是一个线程),从我们坐下开始,服务员就把菜单给你,然后在旁边等你点菜(等待 I/O 操作),当你看完菜单,把要点的菜告诉服务员( I/O 操作结束后线程继续执行)。在你看菜单的过程中,服务员其实是被闲置的,如果你一直看,他就会一直等,直到你点完( I/O 操作结束)。这就是阻塞式 I/O。

小餐馆(Node.js) 一个规模比较小的餐馆,雇不起大量的服务员,只能雇佣一个服务员。当有顾客来时,服务员把菜单送过去,顾客开始看菜单( I/O 操作),这个时候,服务员是被释放了的,他不用等待顾客看菜单,服务员说:“您先看着菜单,点好了叫我”(回调函数)。这个时候这个服务员就可以抽身去服务其他的顾客。用这种模式的话,一个服务员就可以服务多位顾客,而且不需要等待 I/O ,只需要随时监听就行了,顾客点完后会主动叫服务员(执行回调函数)。

Node.js的三大特点

单线程与多线程 高级餐厅是多线程:给每一个用户分配一个服务员(多个服务员,多线程)

小餐馆是单线程:所有用户共享一个服务员(一个服务员,单线程)

阻塞 I/O与非阻塞 I/O 高级餐厅是阻塞 I/O:服务员(线程)在旁边等你点菜(等待 I/O 操作),直到你点完菜( I/O 操作)之后,线程才继续执行。

小餐馆是非阻塞 I/O(异步 I/O):服务员(线程)不等待你点菜(不等待 I/O 操作)而抽身去服务其他的顾客,只需要随时监听,顾客点完后主动叫服务员(执行回调函数)。

事件驱动 但是,还有一个问题就是,如果有多个顾客都在叫小餐馆的一个服务员,该如何响应?肯定要有一定的规则,这就涉及到了 Node.js的事件驱动。

在一些应用场景中,我们希望程序是被“事件”触发运行的,并且程序在感知到不同的“事件”后能够产生不同的响应动作(比如小餐馆的用户点菜完成之后,需要召唤服务员收回点菜单交给后厨),此时就需要应用程序能够实时“感知”其所关心的事件,并在事件发生后执行相应的操作。

在解决上述问题时,应用程序是由“事件”驱动运行的,我们可以将这种编程模型称为事件驱动模型。

事件驱动模型 事件驱动模型大体思路如下:

有一个事件(消息)队列; 当有事件发生时,往这个队列中增加一个事件(消息); 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数; 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数; 事件驱动编程是一种编程范式,程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。

在事件驱动的程序中,各个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。

当我们面对如下的环境时,事件驱动模型通常是一个好的选择: 程序中有许多任务,而且… 任务之间高度独立(因此它们不需要互相通信,或者等待彼此)而且… 在等待事件到来时,某些任务会阻塞。 当应用程序需要在任务间共享可变的数据时,这也是一个不错的选择,因为这里不需要采用同步处理。

网络应用程序通常都有上述这些特点,这使得它们能够很好的契合事件驱动编程模型。

总结 传统的服务器语言大多是多线程、阻塞式 I/O:对于传统的服务器语言,在与用户建立连接时,每一个连接(每一个用户)都是一个线程。 当有十万个用户连接时,服务器上就会有十万个线程。阻塞式 I/O 是指,当一个线程在执行 I/O 操作时,这个线程会阻塞,等待 I/O 操作完成后继续执行。 而Node.js是单线程、非阻塞I/O,这是它与众不同的地方,其最大的优势就是性能强:同样的服务器性能使用Node.js可以比传统的服务器语言多容纳一百倍的用户(对于不同的任务有不同的差别, I/O 操作越多,node优势越明显,如果都是 CPU 计算任务,那他俩几乎没有区别(上面的例子中,忽略顾客的看菜单时间)。 单线程、非阻塞式 I/O 的优势就是性能强,一个人服务员就可以解决大量顾客。但是他的缺点也很明显,比如有一桌顾客和服务员又吵架了(线程崩了!),那这些顾客就都完了,因为所有人都在等这一个服务员。也就是说,如果线程崩掉了,那与这个服务器连接的所有用户都会崩溃(单点故障)。 单线程、非阻塞式 I/O的Node.js的工作方式是事件驱动。

原文链接: 传送门

插件 使用 nodemon 代码实时更新不用重启 npm i nodemon --save-dev 只在开发环境中使用 =》 启动nodemon app.js 可以安装在全局 全局变量 在 node.js 中全局对象不是 window 在 node.js 中全局对象 global 在 node.js 中 声明的函数和变量不会自动添加到全局对象 global 上

全局函数

/** * 全局函数 */ // 1、setTimeout setTimeout(()=>{ console.log(1) },1000) // 2、setInerval setInterval(() => { console.log(2); },1000); // 3、清除定时器 const timer = setInterval(()=>{ console.log(1) },1000) clearInterval(timer) // 4、setImmediate 立即执行. 了解:是在事件队列开始之前执行 setImmediate(()=>{ console.log(1) }) // 5、process.nextTick() 立即执行的. 了解:在主进程结束后立即执行 process.nextTick(()=>{ console.log(2) }) 内置函数

1.conslole.js

// 1、基本用法 console.log(1) const a = "10" console.log("a:",a) console.log("a=%d",a) // 2、格式化输出 const obj = { myName:'zs', age:19, a:"今天学习node.js", b:'明天也学习nodejs', c:{ d:"后天也学习node.js", e:'应该学的不错了', f:{ m:'不知道鞋舌么了' } } } console.log(obj) console.table(obj) // 3、计时函数 console.time() console.time("for") let sum = 0 for(let i=0;i { const url = req.url // 设置默认的响应内容为 404 Not found let content = '404 Not found!' // 判断用户请求的是否为 / 或 /index.html 首页 // 判断用户请求的是否为 /about.html 关于页面 if (url === '/' || url === '/index.html') { content = '首页' } else if (url === '/about.html') { content = '关于页面' } res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end(content) }) server.listen(80, () => { console.log('server running at http://127.0.0.1') }) 文件流的读写方式 /* 文件流的读写方式 */ const fs = require('fs') // todo file2.txt自动创建 // 1、创建读取流 const readStream = fs.createReadStream("./file2.txt") // 2、创建写入流 const writeStream = fs.createWriteStream("./file_stream.txt") // 3、搭建管道把读取流的数据传给写入流 readStream.pipe(writeStream) 模块化 模块化概念

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程,模块是可组合、分解和更换的单元。 模块化可提高代码的复用性和可维护性,实现按需加载。 模块化规范是对代码进行模块化拆分和组合时需要遵守的规则,如使用何种语法格式引用模块和向外暴露成员。

Node.js 中模块的分类

内置模块 自定义模块 第三方模块

Node.js 中的模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域 防止全局变量污染

模块作用域的成员

自定义模块中都有一个 module 对象,存储了和当前模块有关的信息 在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。导入自定义模块时,得到的就是 module.exports 指向的对象。 默认情况下,exports 和 module.exports 指向同一个对象。最终共享的结果,以 module.exports 指向的对象为准。

CommonJS 模块化规范

每个模块内部,module 变量代表当前模块 module 变量是一个对象,module.exports 是对外的接口 加载某个模块即加载该模块的 module.exports 属性

模块加载机制

模块第一次加载后会被缓存,即多次调用 require() 不会导致模块的代码被执行多次,提高模块加载效率。

内置模块加载

内置模块加载优先级最高。

自定义模块加载

加载自定义模块时,路径要以 ./ 或 ../ 开头,否则会作为内置模块或第三方模块加载。

导入自定义模块时,若省略文件扩展名,则 Node.js 会按顺序尝试加载文件:

按确切的文件名加载 补全 .js 扩展名加载 补全 .json 扩展名加载 补全 .node 扩展名加载 报错

第三方模块加载

若导入第三方模块, Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。 如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。 例如,假设在 C:\Users\bruce\project\foo.js 文件里调用了 require('tools'),则 Node.js 会按以下顺序查找:

C:\Users\bruce\project\node_modules\tools C:\Users\bruce\node_modules\tools C:\Users\node_modules\tools C:\node_modules\tools

目录作为模块加载

当把目录作为模块标识符进行加载的时候,有三种加载方式:

在被加载的目录下查找 package.json 的文件,并寻找 main 属性,作为 require() 加载的入口 如果没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会试图加载目录下的 index.js 文件。 若失败则报错



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有