node.js笔记

day1

1.下载node.js

        官网: Node.js (nodejs.org)

        我下的是LTS长期支持版,比较稳定,安装好之后打开cmd输入node -v就可以查看node版本顺便输入一下npm -v看看npm有没有安好,npm是安装node自动下的后面写vue经常用到。

2.版本管理工具

        不支持windows就没下,两个管理工具一个叫nvm另一个叫n(就一个字母没少打)。

3.敲代码!!!

        1.如何在 node 环境下运行js代码

         创建js文件输入下面的内容,很简单的两个打印之前学js在浏览器端经常用console.log()测试

这次在node环境下运行一下试试。

console.log(11111);
console.log(2222);

打开终端cd到相应的文件夹输入文件夹的前几个字然后按tab可以快速定位到文件夹,切换到js文件的上一层文件夹就行了,输入命令node + 文件夹名 就可以输出了。

PS C:\Users\KABUTO\Desktop\codewhy\node.js\01-js代码运行> node .\index.js
11111
2222

        2.给node传递参数

        首先node里面有一个process,我们可以打印一下它。

console.log(process);

得到一个很复杂的对象,其他东西先不管,这个大对象里又一个数组argv我们看一下此时的argv。

argv: [
    'D:\\node\\node.exe',
    'C:\\Users\\KABUTO\\Desktop\\codewhy\\node.js\\02-给node传递参数\\indedx.js'
  ]

里面只有两个路径,如果在运行的时候传两个值进去会怎么样呢。

node .\indedx.js hello kabuto    

此时argv变成了

argv: [
    'D:\\node\\node.exe',
    'C:\\Users\\KABUTO\\Desktop\\codewhy\\node.js\\02-给node传递参数\\indedx.js',
    'hello',
    'kabuto'
  ]

 可以看到刚刚传的两个值以字符串的形式存进了argv里,完成了给node传递参数

        3.node中的全局对象

        两个特殊的全局对象

 __dirname 和 __filename,打印一下

console.log(__dirname);
console.log(__filename);

输出

PS C:\Users\KABUTO\Desktop\codewhy\node.js\03-Node中的全局对象> node .\01_特殊的全局对象.js
C:\Users\KABUTO\Desktop\codewhy\node.js\03-Node中的全局对象
C:\Users\KABUTO\Desktop\codewhy\node.js\03-Node中的全局对象\01_特殊的全局对象.js

可以看出第一个是打印出当前执行命令所在文件夹的路径,第二个是当前命令所执行文件的路径.

         计时器全局对象

setTimeout,setInterval,setImmediate,process.nextTick,计时器,循环计时器,立即执行计时器,还有个不认识的但上面传值的时候打印过这玩意。

看看谁输出比较快。

setTimeout(()=>{console.log('setTimeout');},1000)
setInterval(()=>{console.log('setInterval');},1000)
setImmediate(()=>{console.log('setImmediate');})
process.nextTick(()=>{console.log('process.nextTick');})

结果 

process.nextTick
setImmediate
setTimeout
setInterval
setInterval
setInterval
setInterval
.
.
.

可以看出来不认识的那个比较快,然后是setImmediate立即执行,然后是setTimeout,最后是setInterval,至于为什么第一个比较快,我猜测可能他可能和promise一样是个微任务,老师说后面时间循环会讲。

        global全局对象

据说里面很全,啥都有但打印出来只有一部分,可以去cmd里面输入golbal .然后按两下tab查看里面的东西

        JavaScript的模块化

        这老师说的非常牛,解决了我多年的困扰,当年大一指针啥的没好好学,以后有机会要恶补数据结构。

        js以前是没有模块化的所以很容易出问题比如在同一个目录下创建三个js文件

第一个文件bar.js

var name = 'kabuto'
console.log(name);

第二个文件foo.js

var name = 'ATM'
console.log(name);

第三个文件baz.js

console.log(name);

然后在html里引入这三个文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="foo.js"></script>
<script src="bar.js"></script>
<script src="baz.js"></script>

打开网页控制台会发现

foo.js:2  ATM
bar.js:2  kabuto
baz.js:1  kabuto

明明没有在baz.js里定义name却可以打印出name,这说明在不同js文件里写代码并重复定义了变量很容易让程序出问题,所以出现了很多模块化js的规则。

第一个介绍规则是commonjs,现在用的貌似都是这个。

定义两个文件一个bar.js一个main.js,在bar.js声明两个变量一个函数,并用exports导出去

const name = 'kabuto'
const age = 18
const hhh = '哈哈哈'
function sayHello(name){
    console.log("你好" + name);
}

exports.name = name
exports.age = age
exports.sayHello = sayHello

然后在main.js文件中引用过来,并打印一下

const bar = require('./bar')
console.log(bar.name);
console.log(bar.age);
bar.sayHello('kabuto')

可以得到

kabuto
18
你好kabuto

但如果打印定义了但没有导出的数据

console.log(bar.hhh);

结果

undefined

可以看出来exports导出入才能显示,若直接引用就是未定义

那exports是什么呢我们来打印一下

console.log(exports);

结果

{}

可以看出exports是一个空对象,exports导出的过程就是给一个空对象赋值,然后另一个文件用require将已赋值的exports引入并赋值给bar,那么可以用解构赋值去验证。

const {name,age,sayHello} = require('./bar');
console.log(name);
console.log(age);
sayHello('kabuto')

结果

kabuto
18
你好kabuto

可以看出和上面的结果一样。

exports指向一个空对象,在bar.js里给空对象赋值然后require也指向这个空对象,在空对象发生改变时两个都跟这改变老师举了一个非常通俗易懂的例子来解释

我们重新定义一个对象obj给这个对象来添加两个属性,再定义一个对象info把obj赋值给info,我们改变info中的one属性看看obj会发生什么

const obj = {
    one:'一',
    two:'二'
}
const info = obj
info.one = '三'
console.log(obj.one);

 可以看到当我们改变info中的one时obj中的one也发生了变化,这是为什么呢,其实给是电脑里开辟了一份内存空间,这两个对象都指向这个内存空间,当我们通过info修改这个内存空间时,obj也会发生相应的变化。

 

 同理,我们可以通过计时器来修改exports来验证这一理论,

在bar.js中加入一个计时器

const name = 'kabuto'
const age = 18
function sayHello(name){
    console.log("你好" + name);
}

exports.name = name
exports.age = age
exports.sayHello = sayHello

setTimeout(()=>{
    exports.name = '独角仙'
},1000)

我们在一秒后通过exports将内存空间中的name改成了独角仙,同理我们在main.js中也写一个计时器,在两秒后打印一下name

const bar = require('./bar')
console.log(bar.name);
console.log(bar.age);
bar.sayHello('kabuto')
setTimeout(()=>{
    console.log(bar.name);
},2000)
kabuto
18
你好kabuto
独角仙

可以看出两秒后name变成了独角仙验证了刚刚内存空间的说法

但其实模块化导出的本质并不是exports,而是module.exports,node中通过module.exports=exports让这两个指向了一块内存空间,所以改变exports时require和module.exports会一起发生改变,因为他们指向的内存空间发生了改变。

来验证一下在bar.js中

const name = 'kabuto'
const age = 18
function sayHello(name){
    console.log("你好" + name);
}
exports.name = name
exports.age = age
exports.sayHello = sayHello
setTimeout(()=>{
    exports.name = '独角仙'
},1000)


console.log(module.exports.name + 'm');
setTimeout(()=>{
    console.log(module.exports.name + 'm');
},2000)

 在main.js中引入bar.js

const bar = require('./bar')

运行

kabutom
独角仙m

可以看出第一次打印的是改变之前的name第二次打印的是改变之后的name,exports改变时module.exports会跟着改变,证明了他们指向同一个内存空间,

那么怎么证明module.exports是是模块化导出的本质呢?很简单,我们只要给module.exports开辟一个新的内存空间,若require的指向也发生改变但exports的指向不变,就证明了module.exports才是模块化导出的核心。

bar.js

const name = 'kabuto'
const age = 18
function sayHello(name){
    console.log("你好" + name);
}
exports.name = name
exports.age = age
exports.sayHello = sayHello
module.exports = {
    name:'独角仙',
    age:'81',
    sayHello:function(name){
        console.log('1,2,3,骑士踢');
    }
}

mian.js

const bar = require('./bar')
console.log(bar.name);
console.log(bar.age);
bar.sayHello('骑士踢')

运行

kabuto+ex
18+ex
你好+ex
undefined
独角仙
81
1,2,3骑士踢

虽然中间不知到为什么会有一个未定义,不过问题不大,我们可以看出,改变module.exprots时,main.js中的 require引入也发生了变化,但exports却没有发生变化,所以module.exprots才是模块化导出的本质,老师最后还出了几个小题目检测对内存空间的理解

在bar.js里设置一个定时器一秒后改变name,两秒后再main.js里打印name,打印的name 是原本的name还是改变之后的name呢。

bar.js

let name = 'kabuto'
const age = 18
function sayHello(name){
    console.log("你好" + name);
}
setTimeout(()=>{
    name = 'nihao'
},1000)
exports.name = name
exports.age = age
exports.sayHello = sayHello

main.js

const bar = require('./bar')
console.log(bar.name);
console.log(bar.age);
bar.sayHello('骑士踢')
setTimeout(() => {
    console.log(bar.name);
}, 2000);

打印

kabuto
18
你好骑士踢
kabuto

可以看出name并没有发生改变,因为在exports.name = name时就已经把name传入内存空间里了,一秒中之后改变的是bar.js中的name不是内存空间中的name,所以两秒之后的打印不会发生变化。

day1结束希望明天继续,吼nana。

day2

        工作写静态,下班写node生活实在是太充实了,今天没啥时间只看了一个视频

require的细节

require本质是一个函数,那么require是怎么引入的呢,情况分为3种

情况一

        require(x),其中x是一个核心模块比如path和http,这是require会直接返回核心模块并停止查找。

情况二

        require(x) x以以./ ../ /(根目录)开头,这种情况,分为三步

            第一步:将x当作一个文件在对应目录下查找

            1直接查找文件x

            2查找x.js

            3.x.json

            4.x.node

           如果没有找到就进行第二步

             1.x/index.js

            2.x/index.json

            3.x/index.node

            第三步:都没找到,报错

情况3:直接写个x

            如果不是核心模块就去上一层目录的node_modules里找并一直往上找,到根目录找不到就报错,require引入时会运行引入的代码,引入的会先执行,同一个文件多次引入时会缓存只执行一次,引入的顺序遵循深度优先算法

 就比如说我按上面的图顺序进行引入敲一下代码验证一下

main.js

const aaa = require('./aaa')
const bbb = require('./bbb')

aaa.js

console.log('aaa');
const ccc = require('./ccc')

bbb.js

console.log('bbb');
const ccc = require('./ccc')
const eee = require('./eee')

ccc.js

console.log('ccc');
const ddd = require('./ddd')

ddd.js

console.log('ddd');
const ddd = require('./eee')

eee.js

console.log('eee');
const eee = require('./eee')

那么输出结果是什么呢,打印一下

PS C:\Users\KABUTO\Desktop\codewhy\node.js\04_javaScript-mosule\02-commonjs3> node .\main.js
aaa
ccc
ddd
eee
bbb

可以看到输出结果是aaa->ccc->ddd->eee->bbb这时因为先引入了aaa再引入了bbb所以先执行aaa,在aaa里有引入了ccc,所以执行,以此内推一直执行到eee,之后再一层一层往回查找一直到main.js发现mian.js里还引入了bbb所以再执行bbb至于bbb中引入的ccc,和eee已经引入过了所以不会继续引入,而且有个细节再require上写console.log是会先运行打印后运行导入的。

中午领导要求加功能晚上继续写

 后面到了es6的模块化,也就是平时vue里用的哪些import和export

当我们写html页面时,给页面加一个type = 'module'就可以实现模块化了,Es module是异步的不会阻塞普通的script。

 虽然是第三天了,但还是day2,没时间写了看看休息日能不能把这几天的都补上

es6模块化导出的三种方式

第一种,直接导出

export const name = 'kabuto'

 第二种,{ }统一导出

export{

}//{}不是个对象

{ }不是一个对象 这里和有commonJs有区别

第三种,导出的时候给对象取别名

export{
    name as fName
    age as fAge
    sayHello as fSayHello
}

 常见的三种导入方式

1 improt {} from '路径'
import {name,age,sayHello}//这也不是对象 from '路径' 
2. 导出变量之后可以起别名
import {name as wName,age as wAge,sayHello as wSayHello} from '路径'
3. * as foo
import * as foo from '路径'

 注意,就是如果导出的时候已近给对象取了别名在使用第二种方式导入时就要使用修改过的别名     而写这里文件必须要写后缀,脚手架里才可能不写。

export和import结合使用

export {sum as barSum} from '路径'

default用法,默认导出,一个模块只能有一个

default export function(){
    console.log(1)
}

引入

import '名字' from 路径

平时写项目还是很常用默认暴露然后直接引入的,这个名字可以我们自己取,非常的方便这个方式引入有一个要注意的点,就是不能在if判断里写import,import是解析阶段,不能放在运行阶段里执行,而require的本质是一个函数可以在判断里使用

day3

其实还是第三天,昨天没啥代码,基本都是理论所以写的挺快,上班了,等午休继续写。

在node中支持Es module我们需要进行如下操作

方式一:在package.json中配置type:module (没学)

方式二:文件以.mjs结尾,表示使用的时es module

这里我们来尝试一下

foo.mjs

const name = 'kabuto'
export {name}

 mian.mjs

import {name} from './foo.mjs'
console.log(name);

 运行

kabuto

 可以看出把后缀名改成mjs后就可以正常运行了

commonJs和Es module的交互

commonJs加载Es module

        通常情况下不兼容,但是不绝对反正node不行

Es module加载commonJs通常可以

        试一试Es module加载commonJs

foo.js

const name = 'kabuto'
exports.name =  name;

main.js

import {name} from './foo.js'
console.log(name);

  打印一下

kabuto

 确实是可以的

好,上面就是模块化的全部东西了,偏理论的东西比较多,光听不动手效果也不是很好,下面就开始将node中的常用内置模块了,现在记得不是很清晰了,正好写一遍笔记巩固一下

常见的内置模块

前面说require导入规则的时候提过一下内置模块,要用的时候必须导入一下,这里我们用的就是require导入,

path模块

path是和路径有关的模块它可以获取到路径也可以做路径的拼接,下面我们来演练一下先引入我们的path模块,然后定义两个路径,我们使用resolve就能把两个路径拼接成一个完整的路径。

const path = require('path')
const basePath = '/User/KABUTO'
const filename = 'abc.txt'
//resolve
const filepath = path.resolve(basePath,filename);
console.log(filepath);

打印

C:\User\KABUTO\abc.txt

可以看到拼接成功了,下面我们来介绍path模块里的其他方法,当然也包括resolve

1.获取路径信息

const filenpath = '/User/KABUTO/abg.txt'
console.log(path.dirname(filenpath)); //获取对应文件夹的name
console.log(path.basename(filenpath));//获取文件的名字
console.log(path.extname(filenpath));//获取文件后缀名

打印一下

/User/KABUTO
abg.txt
.txt 

可以看到获取到了相对应的名字,就是单词有点难背。

2.join路径拼接(比较笨)

join可以把两个路径拼接到一起和下面的resolve一样,但是这个方法比较笨不能识别文件前的./之类的路径

const basepath = '../User/why'
const filename = 'abc.txt'
const filepath = path.join(basepath,filename)
console.log(filepath);

打印一下

..\User\why\abc.txt

可以看出来拼接成功了,但它并没有识别出来前面的../可能有些不清晰,但对比一下resolve就可以很明显的看出哪里不一样。

3.resolve路径拼接

resolve会判断拼接的字符串中是否以/或者./或../开头的路径

const basepath = '../User/why'
const filename = 'abc.txt'
const filepath2 = path.resolve(basepath,filename);
console.log(filepath2);

运行一下

C:\Users\KABUTO\Desktop\codewhy\node.js\05_常见的内置模块\User\why\abc.txt

可以看出resolve可以识别路径之前的..并把识别了前面的路径拼接到了路径前面,非常的智能

fs模块

 fs是和文件有关的模块它可以获取到文件也可以操作文件,下面我们来演练一下先引入我们的fs模块,然后来操作一下文件

首先创建一个txt文件在里面写入一些东西

abc.txt

hello world

在js文件中读取这个文件的信息有三种方式

第一种:同步操作

const fs = require('fs')
const filepath = "./abc.txt"
const info = fs.statSync(filepath);
console.log('nihao');
console.log(info);
console.log('nihao');

打印一下

PS C:\Users\KABUTO\Desktop\codewhy\node.js\05_常见的内置模块\02_fs> node .\01_fs的三种使用方式.js
nihao
Stats {
  dev: 3772190872,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: 4096,
  ino: 2251799814976833,
  size: 32,
  blocks: 0,
  atimeMs: 1679109785262.005,
  mtimeMs: 1678893991065.0947,
  ctimeMs: 1678893991065.0947,
  birthtimeMs: 1678892243213.364,
  atime: 2023-03-18T03:23:05.262Z,
  mtime: 2023-03-15T15:26:31.065Z,
  ctime: 2023-03-15T15:26:31.065Z,
  birthtime: 2023-03-15T14:57:23.213Z
}
nihao

可以看到同步读取信息阻塞了打印的执行

第二种:异步操作

const fs = require('fs')
const filepath = "./abc.txt"
console.log('nihao');
fs.stat(filepath,(err,info)=>{
    if(err){
        console.log(err);
        return
    }
    console.log(info);
})
console.log('nihao');

 打印一下

nihao
nihao
Stats {
  dev: 3772190872,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: 4096,
  ino: 2251799814976833,
  size: 32,
  blocks: 0,
  atimeMs: 1679109785262.005,
  mtimeMs: 1678893991065.0947,
  ctimeMs: 1678893991065.0947,
  birthtimeMs: 1678892243213.364,
  atime: 2023-03-18T03:23:05.262Z,
  mtime: 2023-03-15T15:26:31.065Z,
  ctime: 2023-03-15T15:26:31.065Z,
  birthtime: 2023-03-15T14:57:23.213Z
}

可以看到异步操作并没有阻塞同步任务的运行,这涉及到js的事件循环后面老师应该会讲。

 第三种:promise也是异步不会阻塞,输出同上

console.log('nihao');
fs.promises.stat(filepath).then(info => {
    console.log(info);
}).catch(err => {
    console.log(err);
})
console.log('nihao');

我们也可以利用文件描述符来获取文件信息

const fs = require('fs');
fs.open("./abc.txt",(err,fd)=>{
    if(err){
        console.log(err);
        return;
    }
    console.log(fd);
    //通过文件描述符去获取文件的信息
    fs.fstat(fd,(err,info)=>{
        console.log(info);
    })
})

打印一下

3
Stats {
  dev: 3772190872,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: 4096,
  ino: 2251799814976833,
  size: 32,
  blocks: 0,
  atimeMs: 1679109785262.005,
  mtimeMs: 1678893991065.0947,
  ctimeMs: 1678893991065.0947,
  birthtimeMs: 1678892243213.364,
  atime: 2023-03-18T03:23:05.262Z,
  mtime: 2023-03-15T15:26:31.065Z,
  ctime: 2023-03-15T15:26:31.065Z,
  birthtime: 2023-03-15T14:57:23.213Z
}

可以看到他的文件描述符是3,我们也根据文件描述符获取到了文件信息

 fs模块还可以操作文件的内容,比如如果我们想要在abc.txt里写入内容

const fs = require('fs');
const content = "我不好,很合理"
fs.writeFile('./abc.txt',content,{flag:"a"},err => {
    console.log(err);
})

如果输出null代表写入成功了,这里的{flag:"a"}代表不覆盖原有的内容,如果不加原来的内容就会被覆盖掉。

 

 确实加进去了,当然fs也可以读取文件

const fs = require('fs');
const content = "我不好,很合理"
fs.readFile('./abc.txt',{encoding:'utf8'},(err,data) => {
    console.log(data);
})

 确实也可以读出来这里的UTF-8是控制编码格式的,如果不加可能会乱码

fs模块也可以对文件夹进行操作

利用fs可以新建文件夹

const fs = require('fs')
const path = require('path')
//创建文件夹
const dirname = './nihao';
if(!fs.existsSync(dirname)){
    fs.mkdir(dirname,err => {
        console.log(err);
    });
}

这样如果我们同路径中如果没有这个文件夹node就会帮我们创建一个

可以看到创建成功了

我们还可以读取文件夹里的文件

const fs = require('fs')
const path = require('path')
const dirname = './nihao';
fs.readdir(dirname,(err,files) => {
    console.log(files);
})

node 一下

 

 当然如果要想读取文件夹里的文件夹我们可以使用递归,这里我们把读取文件封装成一个函数

function gitFiles(dirname){
    fs.readdir(dirname,{withFileTypes:true},(err,files) => {
        files.forEach((file)=>{
                if(file.isDirectory()){
                    const filepath = path.resolve(dirname,file.name);
                    gitFiles(filepath)
                }else{
                    console.log(file.name);
                }
        })
    })
}
gitFiles(dirname)

运行一下

 成功获取到啦,太不容易了,递归什么的

 我们还能给文件重命名

const fs = require('fs')
fs.rename("./nihao","./hello",err=>{
    console.log(err);
})

运行

 成功改变了文件夹的名字

events的基础方法

const EventEmitter = require("events")
//1.创建发射器
const emitter = new EventEmitter();

//2.监听某一个事件
//addListener时on的alias简写
emitter.on('click',(args)=>{
    console.log('监听到了1的click事件',args);
})

const listener2 = (args)=>{
    console.log("监听到了2",args);
    
}
emitter.on('click',listener2)
//取消监听
emitter.off('click',listener2)
//发出一个事件
emitter.emit("click","kabuto","nihao")

运行一下

 

成功 

day4

讲了一些npm相关的问题

首先我们下载和发布包其实是发布到registry上的
我们通过npm init可以初始化一个npm包,也可以通过npm init -y 直接初始化跳过步骤当我们初始化完成之后会出现package.json文件,这个相信大家并不陌生,写vue项目的时候经常用到,下载了啥都能从里面看到。

{
  "name": "06_npmdemo",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}

         我们可以在在scripts中写入"start": "node index.js"这样就可以使用npm start直接运行文件了

 非常的方便我们在项目里安装一个axios测试一下

 可以看到我们的项目中多了一个node_modules,package.json中的内容也发生了变化

这里也多了一个axios这里的dependencies是无论开发阶段还是生成环境都要用到的包
devDependencies(在package-lock.json里)是生成环境不需要的我们可以看到后面跟了一个版本号,

semver版本规范是X.Y.Z
X是主版本号,当你做了不兼容API修改(可能不兼容以前的版本)
Y是次版本号,当你做了向下兼容的功能新增(新功能增加,但兼容以前的版本)
Z手机修订号:当你做了向下兼容的问题修正(没有新功能修复了bug)
^和~的区别
^是表示x 保持不变Y和Z永远安装最新的版本
~是X和Y保持不变z永远安装最新版本

我们可以通过npm install " "来进行局部安装也可以通过npm install " " -g来进行全局安装,全局安装的一般是类似yarn,webpack这样的包,局部安装的一般则是类似axios这样的包,类似npm的工具还有cnpm和yarn等,这几天状态不是很好,所以听课效率比较差,晚上继续day5的学习。明天应该是封装一个自己的脚手架可能会单独放在一个文章里。

day5

脚手架工具差点给我干放弃了,一开始能听的大差不差,后面真的是离谱,由于是照着敲的没什么思路就直接跳day6了。

day6

今天全是理论,基本没什么代码,只有几道面试题需要敲一下代码,虽然全是理论但非常的重要

进程和线程

可以把进程理解为工厂里的一个车间,线程理解为程序里面运行的车间里的流水线,我们的浏览器一般是多进程,每打开一个新窗口就是一个进程,但javaScript在浏览器中是单线程的,所以任务多的时候可能会卡,这个时候事件循环就非常重要了。

事件循环

事件循环分为浏览器中的事件循环和node中的事件循环,先说浏览器中的事件循环

因为js在浏览器中是单线程的,所以在运行的时候碰到异步任务可能会阻塞,而事件循环可以帮我们解决这个问题,浏览器在运行js的时候会额外开两个队列,宏任务队列和微任务队列,这两个队列用来存放异步任务,如果是同步任务就直接扔到主线程中执行,如果是异步任务,就扔到其他队列里等待,如果达到执行条件再放进主线程,而这两个队列中,微任务队列的优先级又大于宏任务队列所以一些常见的谁先输出的面试题就非常好解决的。

有几个注意点,promise后面直接跟这的算同步任务,.then()后面跟这的才是微任务,await后面跟着的也是同步任务,后面才是微任务。

node中的事件循环

Node.js是单线程的语言,是通过事件循环处理非阻塞I/O操作的。 node中的事件循环主要靠libuv,js代码交给v8解析,v8载传给libuv,libuv再传给操作系统,libuv 里有一个线程池可以拿到异步IO事件轮询然后传给事件循环,所以node中的事件循环多了几个队列,具体记不太清哪几个阶段了反正 同步>process.nextTick()>其他微任务>定时器>IO>setImmediate,但有时有特殊情况就是setImmediate可能会比计数器先输出因为io阻塞。

day7

buffer

buffer用于在内存中存放二进制数据,nodejs不能控制数据传输的时间,若没到发送时间,则数据会存放在Buffer中,直至将数据发送完毕。buffer的初始空间是8kb也就是1024个比特也就是1024x8个比特,总之能存很多字,话不多说我们直接上代码

const message = 'hello'
var buffer = new Buffer(message)
console.log(buffer);

 

 可以看到Buffer后面跟这的两位两位的数字就是buffer非常的工整,但后面会有很多提示我们可以用另一种方式创建buffer来关掉这些提示

const message = 'hello'
var buffer = Buffer.from(message)
console.log(buffer);

 

可以看到这样就没有提示了,这里我们将hello转成了buffer,这里正好五个数字,所以一个字母对应一个数字。

 下面我们来看看buffer的中文编码

const message = "你好"
var buffer = Buffer.from(message)
console.log(buffer);
console.log(buffer.toString());

 

可以看到 一个中文对应三个数字,我们也可以直接.toString()来把我们的buffer转成中文。

我们可以通过某种方式直接创建一个指定大小的buffer里的值通过buffer.alloc创建方式

const buffer = Buffer.alloc(8);
console.log(buffer);
buffer[0]=88
buffer[1]=0x88
console.log(buffer);

 可以看到我们创建完成了并且可以根据索引修改里面的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KABUTO_0717

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值