node.js事件循环详解

谁先执行?

global里的将来执行的函数

setInterval(callback, delay[, ...args])

  • callback 当定时器到点时要调用的函数。
  • delay 调用 callback 之前要等待的毫秒数。
  • …args 当调用 callback 时要传入的可选参数。

预定每隔 delay 毫秒重复执行的 callback。 返回一个用于 clearInterval() 的 Timeout。

当 delay 大于 2147483647 或小于 1 时,delay 会被设为 1。

如果 callback 不是一个函数,则抛出 TypeError。

setTimeout(callback, delay[, ...args])

  • callback 当定时器到点时要调用的函数。
  • delay 调用 callback 之前要等待的毫秒数。
  • …args 当调用 callback 时要传入的可选参数。

预定在 delay 毫秒之后执行的单次 callback。 返回一个用于 clearTimeout() 的 Timeout。

callback 可能不会精确地在 delay 毫秒被调用。 Node.js 不能保证回调被触发的确切时间,也不能保证它们的顺序。 回调会在尽可能接近所指定的时间上调用。

注意:当 delay 大于 2147483647 或小于 1 时,delay 会被设为 1。

如果 callback 不是一个函数,则抛出 TypeError。

  • 上面这两个函数和js里的原生函数用法类似,不做多讲:

util.promisify()让一个遵循异常优先的回调风格的函数, 即 (err, value) => … 回调函数是最后一个参数, 返回一个返回值是一个 promise 版本的函数,即可以在回调结束时通过链式反应调用后续的then()catch()等。

const util = require('util');
const setTimeoutPromise = util.promisify(setTimeout);

setTimeoutPromise(40, 'foobar').then((value) => {
  // value === 'foobar' (passing values is optional)
  // This is executed after about 40 milliseconds.
});

setImmediate(callback[, ...args])

  • callback 在 Node.js 事件循环的当前回合结束时要调用的函数
  • …args 当调用 callback 时要传入的可选参数。

预定立即执行的 callback,它是在 I/O 事件的回调之后被触发。 返回一个用于 clearImmediate() 的 Immediate。

当多次调用 setImmediate() 时,callback 函数会按照它们被创建的顺序依次执行。 每次事件循环迭代都会处理整个回调队列。

如果一个立即定时器是被一个正在执行的回调排入队列的,则该定时器直到下一次事件循环迭代才会被触发。

如果 callback 不是一个函数,则抛出 TypeError。

  • 这个看起来像是新的api是怎么用的呢?我们先看一下它的机制:

我的文件名为index.js

setImmediate(()=>{
    console.log('====================================');
    console.log(1);
    console.log('====================================');
})
console.log(2);

在这里插入图片描述

这个api是在nodejs的事件循环结束后立即调用!!!

同步执行的Promise,异步执行的then

  • Promis对象接收resolve值为1,并触发后续then方法,再看谁先执行:
Promise.resolve(1).then(res =>{
    console.log(res);
    
})
console.log(2);

在这里插入图片描述

Promise是同步,会直接生成一个状态为成功的promise对象,继续向后执行,但是then是异步的,所以会把后面的同步函数方法等执行后再执行then里的代码。

process进程

  • process也是异步的:
process.nextTick(() =>{
    console.log(1);
})
console.log(2);

在这里插入图片描述

到底谁先执行?

我们都多加几个试试:

  • process.nextTick:
process.nextTick(() =>{
    console.log("nextTick 1");
})
process.nextTick(() => {
    console.log("nextTick 2");
})
console.log(2);

在这里插入图片描述

  • 再加个setImmediate:
setImmediate(() => {
    console.log("setImmediate 1")
})
process.nextTick(() =>{
    console.log("nextTick 1");
})
process.nextTick(() => {
    console.log("nextTick 2");
})
console.log(2);

在这里插入图片描述

  • 我们再套个process呢?
setImmediate(() => {
    console.log("setImmediate 1")
})
process.nextTick(() =>{
    console.log("nextTick 1");
})
process.nextTick(() => {
    console.log("nextTick 2");
})

setImmediate(() => {
    console.log("setImmediate 2")
    process.nextTick(() => {
        console.log("nextTick 3");
    })
})
console.log(2);

在这里插入图片描述

乱????

setImmediate(() => {
    console.log("1")
})
process.nextTick(() =>{
    console.log("2");
})
process.nextTick(() => {
    console.log("3");
})

setImmediate(() => {
    console.log("4")
    process.nextTick(() => {
        console.log("5");
    })
})
console.log(6);
//6 2 3 1 4 5
  • 没毛病,再加个settimeout:
setImmediate(() => {
    console.log("1")
})
process.nextTick(() =>{
    console.log("2");
})
process.nextTick(() => {
    console.log("3");
})
setImmediate(() => {
    console.log("4")
    process.nextTick(() => {
        console.log("5");
    })
})
setTimeout(() => {
    console.log(7);
}, 0);
console.log(6);

在这里插入图片描述

事件循环,同步和异步

因为nodejs由事件驱动,它会将所有的事件通过一个对象包装起来,通过循环机制,将事件挨个儿执行,重点就在包装这里!

  • 你可以理解为nodejs有个无限循环的查找函数,不停的将事件推入一个队列,第一次循环将全局事件依照优先级推入队列,第二次循环将事件生成的事件推入队列,依次执行下去!

如何去理解js里的代码都是同步,而真正异步的是回调的触发行为!引发异步其实是异步回调函数!

macro-task:script(脚本代码)>>>>>settimeout/setinterval>>>>>setImmediate>>>>>I/O
micro-task:process>>>>>Promise

  • 为了更清楚的认知到事件循环,我们重新整理代码作为对比:
setImmediate(() => {
    console.log("1")
})
process.nextTick(() =>{
    console.log("2");
})
process.nextTick(() => {
    console.log("3");
})
setImmediate(() => {
    console.log("4")
    process.nextTick(() => {
        console.log("5");
    })
})
setTimeout(() => {
    console.log(6);
    process.nextTick(() => {
        console.log("7");
    })
    setImmediate(() => {
        console.log("8")
    })
}, 0);
setTimeout(() => {
    console.log(9);
    Promise.resolve(10).then(res => {
        console.log(res);
    })
}, 0);
Promise.resolve(11).then(res=>{
    console.log(res);
})
setTimeout(() => {
    console.log(12);
}, 0);

console.log(13);

setInterval(() => {
    console.log(14);
}, 0)//我用Ctrl + C打断持续执行

在这里插入图片描述

  • nodejs里的包装函数的伪代码:

macro-task:script(脚本代码)>>>>>settimeout/setinterval>>>>>setImmediate>>>>>I/O
micro-task:process>>>>>Promise

while(代码还没有结束的监听,没有销毁就返回true){

	第一步:查询整体脚本代码,将事件流推入队列;
	macro:"script(13)">>>setTimeout(6 9 12)、setInterval(14)>>>setImmediate(1 4)
	micro:process(2 3)>>>Promise(11)
	结果打印:13
	
	第二步:执行同步代码,process(),Promise()macro:setTimeout(6 9 12)、setInterval(14)>>>setImmediate(1 4)
	micro:"process(2 3)>>>Promise(11)"
	结果打印:2 3 11
	
	第三步:执行异步代码,setTimeoute()/setInterval(),将新的事件流推入队列;
	macro:"setTimeout(6 9 12)、setInterval(14)" >>>setImmediate(1 4 8)
	micro:++process(7)>>>Promise(10)
	结果打印:6 9 12 14
	
	第四步:执行同步代码,process(),Promise();
	macro:setImmediate(1 4 8)
	micro:"process(7)>>>Promise(10)"
	结果打印:7 10

	第五步:执行异步代码,setImmediate(),将新的事件推入队列;
	macro:"setImmediate(1 4 8)"
	micro:++process(5)
	打印结果:1 4 8

	第六步:执行同步代码,process();
	macro:null
	micro:"process(5)"
	打印结果:5

	第七步:监听事件队列状态
	macro:null
	micro:null
	程序结束 return
	//因而interval是持续循环的函数,所以还会执行,但并不是重新挂载的事件
}

可以看到,每执行一次异步代码都会把同步代码的队列进行执行清空,结果变得显而易见!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奔跑的飞牛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值