⚡node打怪升级系列 - 基础篇

前言

NodeJS这东西是不是学过了,之后感觉又像没学到什么东西???

我最近翻到了之前学习node的笔记,又结合了一些大佬的经验,这里把node系列相关的东西串联一下,分享给小伙伴们,顺便我自己也加深一下印象。

总共分为六篇

node打怪升级系列 - 基础篇

node打怪升级系列 - Koa篇

node打怪升级系列 - 浅谈require函数

node打怪升级系列 - 手写中间件篇

node打怪升级系列 - 手写发布订阅和观察者篇

node打怪升级系列 - 手写compose(洋葱模型)

node打怪升级系列 - 手写简易脚手架篇

本文重点记录下基础篇里的基础知识、事件循环机制等装备

正文开始

1,声明式编程和命令式编程

学NodeJS之前,得换一下编程思维,Node是用命令式编程~~~

前端的编程更倾向于声明式编程,比如大家耳熟能详的Vue

后端的编程更倾向于命令式编程,比如Java, Node

1.1,声明式编程

大白话:去餐厅吃饭,告诉服务员给你上一份北京烤鸭,过一会烤鸭就给你上来了,你不需要关心烤鸭咋做的。

声明数据和一个按钮的逻辑关系,当数据变化时,按钮的状态也会随之变化。开发者并不需要告诉Vue如何具体地去更新这个按钮,只需要声明数据和按钮的关系即可。

js 复制代码
<template>  
  <div>  
    <p>{{ count }}</p>  
    <button @click="increment">Increment</button>  
  </div>  
</template>  
  
<script>  
export default {  
  data() {  
    return {  
      count: 0  
    };  
  },  
  methods: {  
    increment() {  
      this.count++;  
    }  
  }  
};  
</script>

1.2,命令式编程

大白话:跟着菜单一步步学做菜,首先热锅,然后倒油,然后放葱姜蒜....,最后做出来一道菜。(不要钻牛角尖,油还需要大豆去炼制,才能得到)

js 复制代码
class Test {
    public static void main(String[] args) {
        //  run ...
    }
}

总的说,命令式编程更接近本质,声明式编程更接近上层业务。

2,node是什么?

node是单线程吗?这算是一个错误的问题。

Node就是Node.js的简称,它是一个运行环境/宿主环境。Node是基于CommonJS规范。

2.1,宿主环境

宿主环境这个词不知道小伙伴陌生不陌生~~~

平时我们做网页开发的时候,承载网页的宿主环境就是浏览器(Chrome为例)。

宿主环境提供了很多API供开发使用。

2.2,宿主环境和V8引擎的关系

Node和浏览器这两个宿主环境对代码的解析执行都用到了V8引擎

下面看下这两个console.log的执行的过程

js 复制代码
console.log('hello world')
console.log(document.getElementsByTagName('head')[0]);

解析:

  • V8引擎开始进行解析

  • 通过词法分析和语法分析转成AST(抽象语法树)

  • 根据AST得知console 是一个对象,log 是一个函数,hello world 是一个字符串,作为 log 的参数

执行:

  • V8引擎解析完以后是否可以执行,是宿主环境决定的,如果支持,宿主环境会配合V8引擎对console进行打印

上面的hellow world浏览器Node这两个宿主环境中都可以打印

但是document.getElementsByTagNameNode中执行会报错,因为Node这个宿主环境没提供document API

2.3,Node API

写代码的本质就是操作宿主环境的API~~~

Node提供的API主要有:

  • 操作磁盘:fs, path

  • 处理网络: http, net

  • 多进程: cluster

  • 操作系统: os

  • 加密: opensssl

  • 压缩: zlib

  • ...

此处顺便把浏览器提供的API也说下吧:

  • 处理和显示dom:document

  • 窗口:window

  • 屏幕:screen

  • ...

3,buffer

是一个固定长度的缓冲区,对于处理图片、接收文件上传等操作二进制数据时用到的一个东西,用于操作字节。

小伙伴们有个概念就行,常规的业务不太能用到。小伙伴可以收藏起来,先跳过,以后再看

过大的文件,可以用buffer分片传输,可以用stream,stream更合适

3.1,运行流程

以接收文件为例,大致流程:File -> Buffer 的缓冲区 -> wait 进程再去处理

File 到 Buffer

  • 接收读取一个文件时,文件的内容会被读取到Buffer中,用于临时存储数据。

缓冲区(Buffer)

  • 缓冲和暂存数据,使得数据的读取和写入操作更加高效,等待进一步处理。

wait 进程再去处理

  • 当系统资源空闲时,由一个进程来统一异步处理处理这些数据。

3.2,Buffer的使用

基础使用

buf2.copy(targetBuffer, targetStart, sourceStart, sourceEnd);

js 复制代码
// <Buffer e5 b0 98 e8 90 bd> 尘落有六个字节
const bufStr = Buffer.from('尘落'); // 获取字符串的字节 
const new_buf = Buffer.alloc(12); // 分配12个字节的内存。

bufStr.copy(new_buf, 0, 0, 6);
bufStr.copy(new_buf, 6, 0, 6);

bufStr.copy(new_buf, 0, 0, 6); 把尘落的6个字节放到new_buf的6个字节上

bufStr.copy(new_buf, 6, 0, 6); 把尘落的6个字节放到new_buf的6个字节上

读文件的二进制字节

js 复制代码
const fs = require('fs');
const path = require('path');
let buf = Buffer.alloc(30);

fs.open(path.resolve(__dirname, './a.js'), 'r', function (err, rfd) {
  fs.read(rfd, buf, 0, 30, 0, function (err, bytesRead) {
    console.log(rfd, buf);
  })
});

4,事件循环

浏览器和Node的事件循环是不一样的,Node事件循环每次循环前要先执行完同步代码、process.nextTick队列

大白话:Node中的事件循环就是同步代码 微任务 宏任务 process.nextTick setImmediate的执行顺序

优先级:同步队列 > process.nextTick队列 > 微任务队列(Promise队列) > 宏任务(timers队列) > setImmediate(check队列)

Promise队列指的是Promise.then()等微任务队列, new Promise属于同步队列

下面这段代码的执行顺序理清楚,Node事件循环就可以过了

js 复制代码
async function async1() {
  console.log('1'); // 2
  await async2();
  console.log('2'); // 8
}

async function async2() {
  console.log('3'); // 3
}

console.log('4'); // 1
setImmediate(() => {
  console.log('5'); // 11
})

setTimeout(() => {
  console.log('6'); // 10
  setImmediate(() => {
    console.log('7'); // 12
  })
}, 0);


async1();
process.nextTick(() => {
  console.log('8'); // 7
})

new Promise((resolve) => {
  console.log('9'); // 4
  resolve();
  console.log('10'); // 5
}).then(() => {
  console.log('11') // 9
});
console.log('12'); // 6

执行顺序光看上面的代码能理清楚吗?

哈哈, 这里贴下中文解释

第一次循环

循环前执行完同步代码nextTick队列Promise队列

  • 执行同步代码,执行nextTick队列(为空),Promise队列(为空)
  • 打印的内容console.log('4') console.log('1') console.log('3') console.log('9') console.log('10') console.log('12')

执行代码,压入队列

process.nextTick队列

  • console.log('8')

Promise队列

  • console.log('2'), console.log('11')
    • console.log('2')是因为await async2()所以被压入了微任务队列

timer队列

  • setTimeout => "console.log('6')", "setImmediate(() => {console.log('7');})"

check队列

  • setImmediate => console.log('5');

第二次循环

循环前执行完同步代码nextTick队列Promise队列

  • 执行nextTick队列,打印的内容console.log('8')
  • 执行Promise队列,打印的内容console.log('2'), console.log('11')

执行timer队列

  • 执行timer队列过程中发现里面有其他setImmediate插入check队列末尾
  • 打印的内容console.log('6')

此时check队列

  • "setImmediate => console.log('5')", "setImmediate(() => {console.log('7');})"

执行check队列

  • 打印的内容console.log('5'), console.log('7')

5,node可以做什么

这里罗列了一个大佬的回答~~~

  • 前端开发: webpack, rollup

  • 跨端开发: weex, RN

  • 后端开发: koa, express, egg

  • 工具开发: 脚本, 脚手架,命令行

脚手架命令行的文章后面也会更新~~~

完结

这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

相关推荐
麒麟而非淇淋32 分钟前
AJAX 入门 day1
前端·javascript·ajax
2401_8581205334 分钟前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢39 分钟前
【Vue】VueRouter路由
前端·javascript·vue.js
随笔写2 小时前
vue使用关于speak-tss插件的详细介绍
前端·javascript·vue.js
史努比.2 小时前
redis群集三种模式:主从复制、哨兵、集群
前端·bootstrap·html
快乐牌刀片882 小时前
web - JavaScript
开发语言·前端·javascript
秋雨凉人心3 小时前
call,apply,bind在实际工作中可以使用的场景
javascript
miao_zz3 小时前
基于HTML5的下拉刷新效果
前端·html·html5
Zd083 小时前
14.其他流(下篇)
java·前端·数据库
哪 吒3 小时前
华为OD机试 - 第 K 个字母在原来字符串的索引(Python/JS/C/C++ 2024 E卷 100分)
javascript·python·华为od