前端进阶-nodejs

博客说明

文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢!

1、什么是nodejs

Node.js是一个基于V8引擎的JavaScript运行环境。Node. js是一个事件驱动、非阻塞式I/O的模型,轻量而又高效;Node. js的包管理器npm是全球最大的开源库生态系统。

2、为什么出现Node.js?Node.js解决了什么问题?

背景:

node是为了写高性能web服务而生的。一个高性能服务器应该是满足“事件驱动,非阻塞 I/O”模型的。首先第一点,nodejs的开发者Ryan 发现 JS 语言本身的特点就是事件驱动并且是非阻塞 I/O 的,跟他的思路正是绝配。第二点,Chrome 的 JS 引擎,也就是 V8 引擎是开源的,而且性能特别棒。于是 Ryan 就基于 V8 开发了 Node.js 。,Node.js 是 C++ 开发的,一个基于 Chrome V8 引擎的 Javascript 运行环境,或者说是一个 JS 语言解释器。

Web 前端的 JS 代码最终还是运行在浏览器中的,在产品环境下,不依赖于 Node.js 。但是,Node.js 诞生以后,前端大爆发,类似 React/Vuejs 这样的前端框架的开发环境变得非常强大和负责,Node.js 是这些开发环境运行的基础。

  1. NodeJS可以让Javascript提供服务器端的功能,从而使得客户端和服务器端的开发都统一在Javascript之下。明显的就是,对于一个对象,如Person Profile的验证不需要客户端和服务器端实现两套。
  2. NodeJS是基于事件的,不像已有的Web服务器,是基于线程的,即每个请求Request都有一个独立的线程为之服务,这样的情况下一旦同时请求很多,则线程很多,每个线程都需要有各种开销,如内存,CPU等。由于每个请求主要消耗的时间都在访问数据库、文件之类的IO操作,这些操作都是同步的,线程都得等。再则线程之间的切换也是需要时间。总之这种线程模型会导致服务器会变慢。而NodeJS则是事件驱动(event driven),只有一个主进程接收各种请求,每个请求只是简单分配,这个很快,当处理耗时的IO操作时,NodeJS采用异步的方式,也就是说主进程不会等IO操作完成,而是直接返回继续进行请求分配,等IO操作完成的时候再通知主进程进行处理。

3、为什么JavaScript是单线程?

js为什么设置为单线程,怎么实现多线程

  • 防止DOM渲染冲突的问题;
  • Html5中的Web Worker可以实现多线程,但是子线程必须受主线程控制,且不得操作dom,所以这个标准并没有改变js单线程的本质。

进程是操作系统分配资源的单位,线程是调度的基本单位,线程之间共享进程资源

JavaScript是单线程,但是一个进程有多个线程。当你打开浏览器的一个页面,其实就是新创建了一个进程,这个进程包括很多线程,比如ui渲染线程、js引擎线程、http请求线程。

4、深入理解nodejs

Node.js 主线程是单线程的,Node.js 程序并非「单线程」。

参考:图解 Node.js 中的「单线程」 - 掘金 (juejin.cn)

称Node单线程指的是 JavaScript 的执行是单线程的,但 Javascript 的宿主环境并非单线程。Node 程序中包含的线程实际上是:JavaScript 的宿主环境需要的线程 + JavaScript 的执行线程。

其实当你用 node xxx.js 运行程序的时候,操作系统会启动下面 7 个线程:

  • 1 个 Javascript 主线程用于执行用户代码

  • 1 个 watchdog 监控线程用于处理调试信息

  • 1 个 v8 task scheduler 线程用于调度任务优先级,加速延迟敏感任务执行

  • 4 个 v8 线程用来执行代码调优与 GC 等后台任务

libuv 创建了线程池,默认情况下线程池里面有 4 个线程。全部是同步代码,那么只会开启 7 个线程,如果存在异步 I/O 操作,则默认会开启 11 个线程。Node.js 程序并非单线程,只不过主线程是单线程的,所有的异步 I/O操作由 libuv 的线程池中的线程进行处理,然后把运行结果通过回调的方式通知到主线程。

Node.js的运行机制

  • V8引擎解析JavaScript脚本。
  • 解析后的代码,调用Node API。
  • libuv库负责Node API的执行。它将不同的任务分配给不同的worker线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
  • V8引擎再将结果返回给用户。

5、浏览器事件循环

1、同步、异步是什么

  • 同步就是必须等前一件做完了才能做下一任务。
  • 异步:当一个异步任务调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个异步任务有结果后,一般通过状态、通知和回调等来通知调用者。对于异步调用,调用的返回并不受调用者控制。

2、js有一个主线程和调用栈,所有的任务都会被压入到调用栈中,等待被主线程执行。JS 调用栈是一种后进先出的数据结构。当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。同步任务会在调用栈中按照顺序排队等待主线程执行。异步任务则会在异步有了结果后将注册的回调函数添加到任务队列(消息队列)中等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中等待主线程执行。任务队列是先进先出的数据结构。

执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,所有微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

3、Event Loop

调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环。

在事件队列中任务被分为两种:宏任务,微任务参考:什么是宏任务、微任务?宏任务、微任务有哪些?又是怎么执行的?_F N Nancy的博客-CSDN博客

  1. 宏任务(Node、浏览器发起的)setTimeout          setInterval...  I/O(Node.js)
  2. 微任务(js发起的)Promise的回调      process.nextTick(Node.js)

执行顺序:当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。

6、node命令执行js文件

使用js语言编写代码,然后保存成xxx.js文件,然后终端执行node xxx.js即可执行js程序。

7、node.js使用http.createServer搭建简单服务

参考:node.js使用http.createServer搭建简单服务-CSDN博客

Node.js入门笔记整理_node.js基础知识总结笔记-CSDN博客

  • 该方法属于http模块,使用前需要引入http模块(var http= require(“http”) )
  • 使用该函数用来创建一个HTTP服务器,并将 requestListener 作为 request 事件的监听函数。http.createServer([requestListener])
  • requestListener   请求处理函数,自动添加到 request 事件,函数传递两个参数:req  请求对象,想知道req有哪些属性,可以查看 “http.request 属性整合”。 res   响应对象 ,收到请求后要做出的响应。想知道res有哪些属性,可以查看 “http.response属性整合”。

解析GET方法参数

var http = require("http");
var querystring = require("querystring");
const url = require('url');
var server = http.createServer(function (req, res) {
  var urlObj = url.parse(req.url);
  var query = urlObj.query;
  var queryObj = querystring.parse(query);
  res.write("Hello world!" + " " +JSON.stringify(queryObj));
  res.end()
});
 
server.listen(5678);

解析POST方法参数

var http = require("http");
 
var server = http.createServer(function (req, res) {
 
    if (req.url == "/") {
        req.on(‘data‘, function (chunk) {
            body += chunk;
        });
 
        req.on(‘end‘, function () {
            body = JSON.parse(body);
            res.end("Hello world!" + " " +body.user);
        });
    }
});
 
server.listen(8000);

8、nodejs的全局变量与内置模块

参考:Node.js学习总结 - 掘金 (juejin.cn)

8.1、常用全局对象

浏览器中的 JavaScript,全局对象window,其有属性DOM、BOM 、Canvas、xhr、js内置对象

在Node环境中,JavaScript也有唯一一个全局变量:global对象。global对象及其所有属性(即全局变量)都可以在程序的任何地方访问,不需要导入。

process对象

process.nextTick的执行时机类似于promise的执行时机,都是等同步任务执行完毕后再被执行。

Buffer对象

它提供了操作二进制数据的功能。(???)

8.2、内置模块

Node.js开发的目的就是为了用JavaScript编写Web服务器程序,服务器程序必须能接收网络请求,读写文件,处理二进制内容

  • path模块-本地文件目录模块,负责处理操作系统相关的文件路径
  • fs模块——文件系统模块,负责读写文件
  • http模块——网络请求模块,发送和接收网络请求
  • url模块——网络地址模块,解析和生成url对象
  • event模块——事件模块,监听和响应事件
  • stream模块——流模块,标准输入流和标准输出流
  • crypto模块-提供了通用的加密和哈希算法
  • 还有很多,可以参考官网API

 

express模块

直接用内置的 http 模块去开发服务器有以下明显的弊端:

  • 需要写很多底层代码——例如手动指定 HTTP 状态码和头部字段,最终返回内容。如果我们需要开发更复杂的功能,涉及到多种状态码和头部信息(例如用户鉴权),这样的手动管理模式非常不方便
  • 没有专门的路由机制——路由是服务器最重要的功能之一,通过路由才能根据客户端的不同请求 URL 及 HTTP 方法来返回相应内容。但是上面这段代码只能在 http.createServer 的回调函数中通过判断请求 req 的内容才能实现路由功能,搭建大型应用时力不从心

由此就引出了 Express 对内置 http 的两大封装和改进:

  • 更强大的请求(Request)和响应(Response)对象,添加了很多实用方法
  • 灵活方便的路由的定义与解析,能够很方便地进行代码拆分
  • Express内置了路由、静态文件服务、请求数据解析、中间件等功能(还需学习)

Request 请求对象

  • req.body:客户端请求体的数据,可能是表单或 JSON 数据
  • req.params:请求 URI 中的路径参数
  • req.query:请求 URI 中的查询参数
  • req.cookies:客户端的 cookies

 Response 响应对象

  • res.send('HTML String');// 发送一串 HTML 代码
  • res.sendFile('file.zip');// 发送一个文件
  • res.render('index');// 渲染一个模板引擎并发送
  • res.status(404).send('Page Not Found');// 设置状态码为 404,并返回 Page Not Found 字符串

路由机制

在express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。

Express中的路由由3部分组成,分别是 请求的类型,请求的url地址,处理函数。格式如下:

const express = require('express');

const hostname = 'localhost';
const port = 3000;

const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(port, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

中间件:按顺序执行(还需要学习)

app.use() 函数的作用就是来注册 全局中间件

实现:客户端->发起请求 -> 中间件1 -> 中间件2  -> 中间件n ->处理完毕响应这次请求 -> 客户端

可以实现路由模块化

const app = express();

function loggingMiddleware(req, res, next) {
  const time = new Date();
  console.log(`[${time.toLocaleString()}] ${req.method} ${req.url}`);
  next();
}

//全局中间件
app.use(loggingMiddleware);
//loggingMiddleware只会在当前路由生效,这种用法属于局部中级件
app.get('/only', loggingMiddleware, (req, res) => {
        res.send('aaa' + req.startTime)
    })

app.get('/', (req, res) => {
  res.send('Hello World');
});


var express=require('express');
 
//引入模块
var admin =require('./routes/admin.js');
var home =require('./routes/home.js');
 
var app=new express();   //实例化
 
app.use('/home',home);   //前台(路由)  http://localhost:3001/home
app.use('/admin',admin);  //后台(路由)  http://localhost:3001/admin
app.use('/',home);     //默认加载前台(路由)
 
app.listen(3001,'127.0.0.1');
 // http://localhost:3001/admin/user---use.js页面


//模块化

var express = require('express')
var router = express.Router()  //创建路由对象

//挂载用户路由
router.get('/user',function(req,res){
  res.sedn('xxxx')
})
router.post('/user',function(req,res){
  res.sedn('xxxx')
})
//挂载列表路由
router.get('/List',function(req,res){
  res.sedn('xxxx')
})

module.exports = router  // 向外导出路由对象


const router = require('./22模块化的路由') //导入模块
app.use(router)  //使用app.use() 注册路由模块

app.use('/api',userRouter)  //为路由模块添加前缀




koa模块

express已经够优秀了,为什么又演进出了koa呢?

Koa 是 Express 的轻量级版本。它是一个对http进行了封装的中间件框架,没有像 Express 那样的额外模块。

Express
  • Node的基础框架,基础Connect中间件,自身封装了路由、视图处理等功能;
  • 线性逻辑,路由和中间件完美融合,清晰明了;
  • 弊端是callback回调方式,不可组合、异常不可捕获;
Koa
  • 基于node的一个web开发框架,利用co作为底层运行框架,利用Generator的特性,实现“无回调”的异步处理;
  • 利用async函数、Koa丢弃回调函数,增强错误处理;
  • 很小的体积,因为没有捆绑任何中间件;没有路由模块。

9、node版本的管理工具nvm

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值