赞
踩
用于测试数据,比较数据是否相等
1.1 assert(value[, message])
第一个参数是值,第二个参数是异常时抛出的异常信息,第二个参数可不写,不写就是系统默认的错误信息
例子1:
- var assert = require("assert")
-
-
- assert(false,"第一个值为false时以我为错误信息抛出");
终端抛出:
- node:assert:400
- throw err;
- ^
-
- AssertionError [ERR_ASSERTION]: 第一个值为false时以我为错误信息抛出
- at Object.<anonymous> (F:\nodeDemo\16.assert.js:7:1)
- at Module._compile (node:internal/modules/cjs/loader:1126:14)
- at Object.Module._extensions..js (node:internal/modules/cjs/loader:1180:10)
- at Module.load (node:internal/modules/cjs/loader:1004:32)
- at Function.Module._load (node:internal/modules/cjs/loader:839:12)
- at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
- at node:internal/main/run_main_module:17:47 {
- generatedMessage: false,
- code: 'ERR_ASSERTION',
- actual: false,
- expected: true,
- operator: '=='
- }
把值改成true时,执行后面的代码
1.2 assert.ok(value[, message])
用法与assert(value[, message])一样
1.3 assert.equal(actual, expected[, message])
用于测试预期值与实际值是否相等,如果相等则断言通过,否则抛出message,相等于==
例子:
- var assert = require("assert")
-
- var a = 1+1
-
- assert.deepEqual(a,1,'值不相等')
1.4 assert.deepEqual(actual, expected[, message])
用于测试预期值与实际值是否相等,相当于==
与equal的区别,deepEqual比较的是对象的属性值
- const obj={a:1};
- const obj2={a:1};
- assert.equal(obj,obj2,'equal 不等');//false
- assert.deepEqual(obj,obj2,'deepEqual 不等')//true
1.5 assert.deepStrictEqual(actual, expected[, message])
用于测试预期值与实际值是否相等,相当于===
1.6 assert.strictEqual(actual, expected[, message])
用于测试预期值与实际值是否相等,相当于===
1.7 assert.notEqual(actual, expected[, message])
创建Buffer对象
2.1 Buffer.from()
支持String、Array、ArrayBuffer、Object、buffer五种类型
--Buffer.from(String [,encoding]);
--Buffer.from(Array);
--Buffer.from(object[, offsetOrEncoding[, length]]);
2.2 Buffer.alloc(size[, fill[, encoding]])
2.3 Buffer.allocUnsafe()
2.4 Buffer.allocUnsafeSlow()
Buffer对象的属性和方法
2.5 Buffer.concat(list[, totalLength])
这是一个拼接Buffer的静态方法,参数list是所有拼接的Buffer对象的列表,totalLength是指定拼接成新的Buffer对象的长度,如果长度不够则会忽略后面数据
2.6 Buffer.isBuffer(obj)
这是一个Buffer静态方法,用来判断对选是否是一个Buffer对象。
2.7 Buffer.keys()
这是一个Buffer对象方法(公有方法),用来获取Buffer对象的key迭代器
2.8 buf.subarray(start,end)
subarray获取Buffer对象中的指定片段,与字符串拼接时会默认调用toString方法
string_decoder可以解决拼接时乱码
child_process
模块用于新建子进程,
子进程的运行结果储存在系统缓存之中(最大200KB)
,等到子进程运行结束以后,主进程再用回调函数
读取子进程的运行结果。
3.1 child_process.exec(command[, options][, callback])
执行的是非node程序,是一个shell命令,执行结果以回调的形式返回。
3.2 child_process.execFile(file[, args][, options][, callback])
执行的是非node程序,是一个可执行文件或应用,执行结果以回调的形式返回
3.3 child_process.spawn(command[, args][, options])
执行的是非node程序,是一个shell命令,不需要获取执行结果,执行结果以流的形式返回。
3.4 child_process.fork(modulePath[, args][, options])
执行的是node程序,是一个.js文件,不需要获取执行结果,执行结果以流的形式返回,fork出来的进程一定是node进程。
子进程与父进程相互通信
在子进程中:
通过process.on('message')和process.send()的机制来接收和发送消息。
在父进程中:
通过child.on('message')和process.send()的机制来接收和发送消息。
4.cluster
4.1 isMaster,isWorker
区分时主进程还是工作进程
4.2 fork()
主进程中创建一个工作进程
4.3 kill()
终止工作进程
- const crypto = require('crypto');
-
-
- function encrypto(key,data) { // 加密函数
- //key : 公钥 data:需要加密的数据,buffer格式
- return crypto.publicEncrypt(key,Buffer.from(data));
- }
-
- function decrypto(key,encrypted) { //解密函数
- //key : 私钥 encrypted: 解密的数据 , buffer格式
- return crypto.privateDecrypt(key,encrypted)
- }
-
- const str = '我真帅'//需要加密的
-
- const cryptoed = encrypto(public_key,str) //公钥加密
- const decryptoed = decrypto(private_key,cryptoed) //私钥解密
一个对象通过这个模块,向另一个对象传递消息
eventEmitter.on() 用于注册监听器
eventEmitter.emit()
用于触发事件
eventEmitter.once() 只触发一次
自定义的类或者对象都是没有实现或继承 Events 模块的,想要使用 Events 模块就需要先导入该模块。
类的继承event
- const event = require('events')
-
- class People extends event {
- constructor(name) {
- super()
- this.name = name
- this.on('eat', this.eat)
-
- }
-
- eat() {
- console.log(`${this.name} eat `);
- this.emit('age')
- }
-
- }
-
- module.exports = People
使用:
- const PeopleEvent = require('./peopleevent ')
-
- const tom = new PeopleEvent('tom')
-
- tom.on('age', () => {
- console.log(`${tom.name}'age is 18 `);
- })
-
- tom.emit('eat')
输出:
tom eat
tom'age is 18
还可以使用util
的inherits
方法继承(这种时过时的)
- const eventEmitter = require('events').EventEmitter
- const util = require('util')
-
- const people = function People(name) {
-
- this.name = name
- this.on('eat', eat)
-
- function eat() {
- console.log(`${this.name} eat `);
- this.emit('age')
- }
- }
-
- util.inherits(people, eventEmitter)
- module.exports = people;
使用:
- const People = require('./60.event')
-
- const tom = new People('Tom')
-
- tom.on('age', () => {
- console.log(`${tom.name}'age is 18 `);
- })
-
- tom.emit('eat')
输出时同样的
tom eat
tom'age is 18
需要先注册在发布
fs.readFileSync(fileName, "utf8");
用于同步读取文件,返回一个字符串
第一个参数是文件路径,第二个参数是文本文件编码
,默认为utf8
fs.writeFileSync(fileName, str, 'utf8');
同步写入文件
它的第一个参数是文件路径,第二个参数是写入文件的字符串,第三个参数是文件编码,默认为utf8
fs.exists(path, callback)
判断给定路径是否存在,然后不管结果如何,都会调用回调函数
fs.exists('/path/to/file', function (exists) {}
exists是一个布尔值
不要在open方法之前调用exists方法,open方法本身就能检查文件是否存在
fs.readFile(path[,options],callback)
用于异步读取文件
- let fs = require('fs');
- fs.readFile('example_log.txt', function (err, logData) {
- if (err) throw err;
- let text = logData.toString();
- });
fs.writeFile(file,data[,options],callback)
用于异步写入文件
fs.stat
检测文件还是目录/文件大小等
fs.mkdir
创建目录
mkdir接受三个参数,第一个是目录名,第二个是权限值,第三个是回调函数
0777 表示可读可写可执行
0666 表示可读可写
- let fs = require('fs');
- fs.mkdir('./helloDir',0777, function (err) {
- if (err) throw err;
- });
fs.appendfile 追加文件
fs.readdir读取目录
fs.rename
fs.rmdir
删除目录 注意:目录下必须为空,才删除
fs.unlink 删除文件
require() 引入模块
module.exports 导出模块或值
Node
为每个模块提供一个exports
变量,指向module.exports
。这等同在每个模块头部,有一行这样的命令
let exports = module.exports;
不能直接将exports
变量指向一个值,因为这样等于切断了exports与module.exports
的联系
内置的require
命令用于加载模块文件
require
命令用于加载文件,后缀名默认为.js
let foo = require('foo'); // 等同于 let foo = require('foo.js');
根据参数的不同格式,require
命令去不同路径寻找模块文件:
“/”
开头,则表示加载的是一个位于绝对路径
的模块文件。比如,require('/home/marco/foo.js')
将加载/home/marco/foo.js
“./”
开头,则表示加载的是一个位于相对路径
(跟当前执行脚本的位置相比)的模块文件。比如,require('./circle')
将加载当前脚本同一目录的circle.js
。“./“或”/“
开头,则表示加载的是一个默认提供的核心模块
(位于Node的系统安装目录中),或者一个位于各级node_modules
目录的已安装模块(全局安装或局部安装)。“./“或”/“
开头,而且是一个路径,比如require('example-module/path/to/file')
,则将先找到example-module
的位置,然后再以它为参数,找到后续路径Node
会尝试为文件名添加.js、.json、.node
后,再去搜索。.js
件会以文本格式的JavaScript
脚本文件解析,.json
文件会以JSON
格式的文本文件解析,.node
文件会以编译后的二进制文件解析。require
命令加载的确切文件名,使用require.resolve()
方法。net.Server 创建服务器
1) 创建Server:var server = net.Server();
2) 监听已有的连接:server.listen(端口号,ip);
3) 监听事件使用on:
事件有: listening:当服务绑定后触发
connection:当一个新的connection(连接)建立的时候触发,有参数socket
close: 当server关闭的时候触发,注意要等到所有的连接都结束之后才触发
error: 当错误出现的时候触发
4) 方法:
listen:监听已有的连接
close:关闭连接
address:返回绑定的地址,只有在listening事件被触发的时候菜可以调用该事件,不然返回的是一个空对象
net.socket 可以被用户创建并直接与server通信,通过[net.createConnection()
][]返回的
1) 创建一个连接:net.connect(端口号,ip);
2) 监听事件使用on:
事件有: connect:当一个socket连接成功建立的时候触发该事件
data:当接收到数据的时候触发该事件,数据编码由 socket.setEncoding() 设置
end: 关闭连接
timeout:连接超时触发
error:
3) 方法:
connect(端口,IP):创建连接
write(内容,编码格式-默认UTF8):在socket上发送数据
setTimeout():设置超时时长
4) 属性:
localPort:用数字表示本地端口。例如80或21
localAddress:返回操作系统报告的 socket 的地址、地址族和端口。返回的对象有三个属性,例如: { port: 12346, family: ‘IPv4’, address: ‘127.0.0.1’ }
remotePort:用数字表示远程端口
remoteAddress:用字符串表示远程IP地址
path.basename(path[, ext]) 返回文件名字,添加第二个参数去掉文件后缀
path.dirname() 返回父路径
path.extname()
方法返回 path
的扩展名
path.format()
方法会从一个对象返回一个路径字符串
path.isAbsolute()
方法会判定 path
是否为一个绝对路径
path.join()
方法使用平台特定的分隔符把全部给定的 path
片段连接到一起,并规范化生成的路径
path.parse()
方法返回一个对象,对象的属性表示 path
的元素
- path.parse('/home/user/dir/file.txt');
- // 返回:
- // { root: '/',
- // dir: '/home/user/dir',
- // base: 'file.txt',
- // ext: '.txt',
- // name: 'file' }
path.relative()
方法返回从 from
到 to
的相对路径
path.resolve()
方法会把一个路径或路径片段的序列解析为一个绝对路径
给定的路径的序列是从右往左被处理的,后面每个 path
被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo
、/bar
、baz
,则调用 path.resolve('/foo', '/bar', 'baz')
会返回 /bar/baz
。
querystring.escape(str) 对给定的 str
进行 URL 编码。
querystring.parse(str[, sep[, eq[, options]]]) 该方法会把一个 URL 查询字符串 str
解析成一个键值对的集合
querystring.stringify(obj[, sep[, eq[, options]]]) 该方法通过遍历给定的 obj
对象的自身属性,生成 URL 查询字符串
- querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
- // 返回 'foo=bar&baz=qux&baz=quux&corge='
基本用法:
- //引入readline模块
- const readline = require('readline');
- //创建readline接口实例
- let r1 = readline.createInterface({
- input:process.stdin,
- output:process.stdout
- });
- //使用question方法
- r1.question('你想吃什么?',function (anwser){
- console.log(`我想吃${anwser}`);
- //添加close事件,不然不会结束
- r1.close();
- });
- //close事件监听
- r1.on('close',function (){
- //结束程序
- process.exit(0);
- });
readline.Interface
类的实例是使用 readline.createInterface()
方法构造的
当 'close'
事件被触发时,readline.Interface
实例会被结束
line事件:每当 input
流接收到接收行结束符(\n
、\r
或 \r\n
)时触发 'line'
事件。 通常发生在用户按下 <Enter>
键或 <Return>
键。
注册line事件:
- rl.on('line', (input) => {
- console.log(`接收到:${input}`);
- });
rl.question()
方法通过写入到 output
来展示 query
,并等待用户提供到 input
的输入,然后调用 callback
函数并传入提供的输入作为第一个参数。
Node.js 中有四种基本的流类型:
pipe:在可读流(readable stream)上调用 stream.pipe() 方法,并在目标流向 (destinations) 中添加当前可写流 ( writable ) 时,将会在可写流上触发 'pipe'
事件
readableSrc.pipe(writableDest)
可读流
- const fs = require('fs');
- const file = fs.createReadStream('./msg.txt', {
- flags: 'r', // 文件的操作方式,同readFile中的配置一样,这里默认是可读的是 r
- encoding: 'utf-8', // 编码格式
- autoClose: true, // 是否关闭读取文件操作系统内部使用的文件描述符
- start: 0, // 开始读取的位置
- end: 5, // 结束读取的位置
- highWaterMark: 1 // 每次读取的个数
- });
-
- file.on('open', () => {
- console.log('开始读取文件');
- });
-
- file.on('data', (data) => {
- console.log('读取到的数据:');
- console.log(data);
- });
-
- file.on('end', () => {
- console.log('文件全部读取完毕');
- });
-
- file.on('close', () => {
- console.log('文件被关闭');
- });
-
- file.on('error', (err) => {
- console.log('读取文件失败');
- });
暂停事件 file.pause();重新读取,需要使用 resume()方法
可写流
- const fs = require('fs')
-
- let rs = fs.createReadStream('./tools/赵雷 - 成都.mp3', { highWaterMark: 1024 })
-
- let ws = fs.createWriteStream('./chengdu.mp3', { highWaterMark: 1024 })
-
- function sleep ( n,rs ) {
- let start = new Date().getTime() ;
- while ( true ) {
- if ( new Date( ).getTime( ) - start > n ) {
- console.log('恢复');
- rs.read()
- rs.resume()
- break;
- }
- }
- }
-
- let i = 0
- console.log('初始',i)
- rs.on('data', function(chunk) {
- console.log('读取1024', i)
- i++
- console.log('当前长度', i)
- if (10 === i) {
- rs.pause()
- sleep(2000, rs)
- }
- console.log('读取进度', Math.trunc( (i * 1024)/13393628 * 100 ),'%')
- // 当ws.write() 返回false时,表示没有空间继续写入了,暂停读取
- if(ws.write(chunk) == false) {
- console.log('暂停rs的data事件');
- rs.pause() // 暂停rs的data事件
- }
- })
-
- ws.on('drain', function() {
- rs.resume() // 恢复rs的data事件 // 把当前读入的内容都写到文件中了,继续调用读写
- })
- // 当读取流触发end方法,表示读取完毕,这时关闭可写流的写入
- rs.on('end', function() {
- ws.end()
- })
管道流
- const fs = require('fs');
-
- // 读取msg.txt中的字符串 hello world
- const msg = fs.createReadStream('./msg.txt', {
- highWaterMark: 5
- });
-
- // 写入到1.txt中
- const f1 = fs.createWriteStream('./1.txt', {
- encoding: 'utf-8',
- highWaterMark: 1
- });
-
- const res = msg.pipe(f1);
- console.log(res);
预定立即执行的 callback
,它是在 I/O 事件的回调之后被触发
setInterval(callback, delay[, ...args])
预定每隔 delay
毫秒重复执行的 callback
setTimeout(callback, delay[, ...args])
预定在 delay
毫秒之后执行的单次 callback
new URL(input[, base])
- const { URL } = require('url');
- const myURL = new URL('/foo', 'https://example.org/');
- // https://example.org/foo
process
对象是Node的一个全局对象,提供当前Node
进程的信息。它可以在脚本的任意位置使用,不必通过require
命令加载。该对象部署了EventEmitter
接口。
process.argv:返回当前进程的命令行参数数组。
process.env:返回一个对象,成员为当前Shell的环境变量,比如process.env.HOME。
process.installPrefix:node的安装路径的前缀,比如/usr/local,则node的执行文件目录为/usr/local/bin/node。
process.pid:当前进程的进程号。
process.platform:当前系统平台,比如win32。
process.title:默认值为“node”,可以自定义该值。
process.version:Node的版本,比如v16.17.1。
process.stdout: 标准输出,它的write方法等同于console.log,可用在标准输出向用户显示内容
process.stdout.write('ssssss');//console.log('ssssss);
输出文件
- fs.createReadStream('./files/input.txt')
- .pipe(process.stdout)
process.stdin: 标准输入
- process.stdin.setEncoding('utf8');
- let fs = require('fs');
- process.stdin.on('readable', function() {
- let chunk = process.stdin.read();
- if (chunk !== null) {
- process.stdout.write('data: ' + chunk);
- }
- });
将键盘输入的显示在控制台
process.stdin.pipe(fs.createWriteStream('./files/input3.txt'))
将键盘输入的显示在文件上
process.stderr: 指向标准错误
process.chdir():切换工作目录到指定目录。
process.cwd():返回运行当前脚本的工作目录的路径。
process.exit():退出当前进程。
process.getgid():返回当前进程的组ID(数值)不支持window系统
process.getuid():返回当前进程的用户ID(数值)。
process.nextTick():指定回调函数在当前执行栈的尾部、下一次Event Loop之前执行。
process.on():监听事件,并指定回调函数 比如uncaughtException。
process.setgid():指定当前进程的组,可以使用数字ID,也可以使用字符串ID。
process.setuid():指定当前进程的用户,可以使用数字ID,也可以使用字符串ID。
process.exit() 来指定退出代码,直接退出,这会导致事件循环中的任务直接不被处理,以及可能导致数据的截断和丢失
正确安全的处理是,设置 process.exitCode,并允许进程自然退出
当前进程退出时,会触发exit
事件,可以对该事件指定回调函数
- process.on('exit', function () {
- fs.writeFileSync('/tmp/myfile', '需要保存到硬盘的信息');
- });
注意
,此时回调函数只能执行同步操作
,不能包含异步操作,因为执行完回调函数,进程就会退出,无法监听到回调函数的操作结果
当 Node.js 清空其事件循环并且没有其他工作要安排时,会触发 beforeExit 事件。例如在退出前需要一些异步操作,那么可以写在 beforeExit 事件中
- let hasSend = false;
- process.on("beforeExit", () => {
- if (hasSend) return; // 避免死循环
-
- setTimeout(() => {
- console.log("mock send data to serve");
- hasSend = true;
- }, 500);
- });
-
- console.log(".......");
- // 输出:
- // .......
- // mock send data to serve
异常处理 try-catch 捕获异常,如果异常未捕获,可以通过监听 process 的 uncaughtException 事件,来处理未捕获的异常
- process.on("uncaughtException", (err, origin) => {
- console.log(err.message);
- });
-
- const a = 1 / b;
- console.log("abc"); // 不会执行
process.nextTick 把回调函数作为微任务,放入事件循环的任务队列中
结合使用:
- process.on('uncaughtException', (err, origin)=>{
- console.log(err.message);
- })
-
- process.nextTick(function () {
- console.log("next tick1");
- sess()
- console.log("next tick11"); //不会执行
- });
-
- process.nextTick(function () {
- console.log("next tick2");
- });
-
- console.log("immediate");
输出:
immediate
next tick1
sess is not defined
next tick2
同步阻塞方式:
比如,你打电话问老婆今晚吃什么,老婆在电话那边一直想啊想,你在电话这边不干别的,就一直等啊等,电话始终未挂,直到她说吃火锅,电话才挂掉。
同步非阻塞方式:
比如,你打电话问老婆今晚吃什么,老婆在电话那边一直想啊想,你在电话这边该干什么干什么,电话始终未挂,直到她说吃火锅,电话才挂掉。
异步阻塞方式:
比如,你打电话问老婆今晚吃什么,老婆说我想想,过一会跟你打话。你在电话这边什么也没干,就一直等着这个电话。
异步非阻塞方式:
比如,你打电话问老婆今晚吃什么,老婆说我想想,过一会跟你打话。你在电话这边想干什么干什么,如果有电话来了,再处理电话。
同步与异步是被调用方决定的,决定是马上给你答案,还是过会通知你,给你答案。
阻塞与非阻塞是调用方决定的,在等待结果的过程中, 是否还可以干其他事。
同步阻塞例子:
- console.log('开始读文件');
- let fileContext = fs.readFileSync('./files/input.txt')
- console.log('input.txt 文件内容',fileContext.toString());
- console.log('程序其他操作');
- let file2Context = fs.readFileSync('./files/output.txt')
- console.log('output.txt 文件内容',file2Context.toString());
- console.log('程序结束');
异步非阻塞例子:
- function ReadInput(){
- fs.readFile('./files/input.txt',(err,data)=>{
- console.log('input文件内容',data.toString());
- })
- }
- function ReadOutput(){
- return fs.readFile('./files/output.txt',(err,data)=>{
- console.log('output文件内容',data.toString());
- })
- }
- console.log('开始读input文件');
- ReadInput()
- console.log('开始读output文件');
- ReadOutput()
- console.log('程序结束');
参考:https://www.jianshu.com/p/d9029f7227ea
https基于http的加密请求方式
http2是一个请求可以有多个响应
序号 | 方法 & 描述 |
---|---|
1 | os.tmpdir() 返回操作系统的默认临时文件夹。 |
2 | os.endianness() 返回 CPU 的字节序,可能的是 "BE" 或 "LE"。 |
3 | os.hostname() 返回操作系统的主机名。 |
4 | os.type() 返回操作系统名 |
5 | os.platform() 返回编译时的操作系统名 |
6 | os.arch() 返回操作系统 CPU 架构,可能的值有 "x64"、"arm" 和 "ia32"。 |
7 | os.release() 返回操作系统的发行版本。 |
8 | os.uptime() 返回操作系统运行的时间,以秒为单位。 |
9 | os.loadavg() 返回一个包含 1、5、15 分钟平均负载的数组。 |
10 | os.totalmem() 返回系统内存总量,单位为字节。 |
11 | os.freemem() 返回操作系统空闲内存量,单位是字节。 |
12 | os.cpus() 返回一个对象数组,包含所安装的每个 CPU/内核的信息:型号、速度(单位 MHz)、时间(一个包含 user、nice、sys、idle 和 irq 所使用 CPU/内核毫秒数的对象)。 |
13 | os.networkInterfaces() 获得网络接口列表。 |
- var os = require("os");
-
- // CPU 的字节序
- console.log('endianness : ' + os.endianness());
-
- // 操作系统名
- console.log('type : ' + os.type());
-
- // 操作系统名
- console.log('platform : ' + os.platform());
-
- // 系统内存总量
- console.log('total memory : ' + os.totalmem() + " bytes.");
-
- // 操作系统空闲内存量
- console.log('free memory : ' + os.freemem() + " bytes.");
js作为浏览器脚本,决定了它只能是单线程的,一些耗时任务会导致浏览器卡顿.因此js将任务分成了同步任务和异步任务.
同步和异步任务分别进入不同的执行”场所”,同步的进入线程,异步的进入任务列表,当线程里面的任务执行完成,从异步任务列表拿出任务在线程里面执行,当前的任务执行完成在从任务列表拿出来在线程里面执行,这个过程就是事件循环
异步任务又分为宏任务和微任务,不同的任务进入不同的任务栈.先执行所有的微任务,在进入宏任务执行微任务...
Promise 新建一个实例时,会立即执行
- setTimeout(function() {
- console.log('setTimeout');
- })
- new Promise(function(resolve) {
- console.log('promise');
- resolve()
- }).then(function() {
- console.log('then');
- })
- console.log('console');
-
- //结果
- promise
- console
- then
- setTimeout
1.这段代码作为宏任务,进入主线程
2.先遇到setTimeout,加入宏任务队列
3.接下来遇到了Promise,new Promise立即执行,then函数加入到微任务队列
4.遇到console.log()同步任务,立即执行
5.好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行
5.ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行
结束
- console.log('1');
- setTimeout(function() {
- console.log('2');
- process.nextTick(function() {
- console.log('3');
- })
- new Promise(function(resolve) {
- console.log('4');
- resolve();
- }).then(function() {
- console.log('5')
- })
- })
- process.nextTick(function() {
- console.log('6');
- })
- new Promise(function(resolve) {
- console.log('7');
- resolve();
- }).then(function() {
- console.log('8')
- })
-
- setTimeout(function() {
- console.log('9');
- process.nextTick(function() {
- console.log('10');
- })
- new Promise(function(resolve) {
- console.log('11');
- resolve();
- }).then(function() {
- console.log('12')
- })
- })
// 1 7 6 8 2 4 3 5 9 11 10 12
1.这段代码作为宏任务,进入主线程
2.遇到console.log()同步任务,立即执行 输出1
3.遇到setTimeout,添加到到宏任务Event Queue
4.遇到process.nextTick,添加到到微任务Event Queue
5.遇到new Promise,立即执行,输出7
6.then函数加入到微任务队列
7.遇到setTimeout,添加到到宏任务Event Queue
8.好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?上面的4和6是微任务,
按先后顺序输出6,8
9.第一轮事件循环结束,开始第二轮,查找序号3宏任务执行,遇到console.log()同步任务,输出2
10.遇到process.nextTick,加入到微任务队列
11.遇到new Promise,立即执行,输出4
12.then函数加入到微任务队列
13.ok,当前的宏任务结束,查看微任务,查看微任务序号10,11,按顺序输出3,5
14.微任务执行完成,开始下一个宏任务setTimeout,序号7,,遇到console.log()同步任务,输出9
15.后面的与第一个setTimeout一样,输出11,10,12
微任务队列中,process.nextTick执行优先级高于其他微任务
宏任务根据类型不同分为以下几种:
Timers 类型的宏任务队列
setTimeout()
setInterval
Check 类型的宏任务队列
setImmediate()
Poll 类型的宏任务队列
除了上面几种的其他所有回调
宏任务里面执行顺序:Timers --> Poll -->Check---
Timers 阶段执行将到期任务从任务栈取出执行
poll 阶段执行到期回调
- const fs=require('fs')
- fs.readFile('test.txt',()=>{
- console.log(' 0')
- setTimeout(()=>{
- console.log(' 1');
- })
- setImmediate(()=>{
- console.log(' 2')
- })
- setTimeout(()=>{
- console.log(' 3');
- })
- })
- setTimeout(()=>{
- console.log(' 4');
- })
-
- setTimeout(()=>{
- console.log(' 5');
- },100)
-
-
- setImmediate(()=>{
- console.log(' 6')
- })
-
- console.log(' 7');
1.进入主线程,readFile加入宏任务
2.setTimeout加入异步宏任务
3.setTimeout加入异步宏任务
4.setImmediate加入异步宏任务
5.同步任务,直接输出7
6.time阶段检测到到期的任务,输出4
7.poll阶段 读取文件还没有完成
8.check阶段 setImmediate输出6
9.进入下轮循环,setTimeout还没有到期
10.进入poll阶段,读取文件完成,输出0
11.check阶段 setImmediate输出2
12.将读文件回调里面的setTimeout加入宏任务队列
13.进入下轮循环,执行到期的setTimeout,输出1,3
14..进入poll阶段,没有任务,check阶段没有任务,下轮循环
15..time阶段检测到到期的任务,输出5
结果: 7 4 6 0 2 1 3 5
如果将打印1的事件间隔100执行,即
- const fs=require('fs')
- fs.readFile('test.txt',()=>{
- console.log(' 0')
- setTimeout(()=>{
- console.log(' 1');
- },100)
- setImmediate(()=>{
- console.log(' 2')
- })
- setTimeout(()=>{
- console.log(' 3');
- })
- })
- setTimeout(()=>{
- console.log(' 4');
- })
-
- setTimeout(()=>{
- console.log(' 5');
- },100)
-
-
- setImmediate(()=>{
- console.log(' 6')
- })
-
- console.log(' 7');
输出结果: 7 4 6 0 2 3 5 1
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。