js事件循环

宏任务:setTimeout,setInterval,setImmediate,I/O,UI渲染,网络请求
微任务:Promise,process.nextTick,MutationObserver、async/await

  1. 首先,js是单线程的,主要的任务是处理用户的交互,而用户的交互无非就是响应DOM的增删改,使用事件队列的形式,一次事件循环只处理一个事件响应,使得脚本执行相对连续,所以有了事件队列,用来储存待执行的事件,那么事件队列的事件从哪里被push进来的呢。那就是另外一个线程叫事件触发线程做的事情了,他的作用主要是在定时触发器线程、异步HTTP请求线程满足特定条件下的回调函数push到事件队列中,等待js引擎空闲的时候去执行,当然js引擎执行过程中有优先级之分,首先js引擎在一次事件循环中,会先执行js线程的主任务,然后会去查找是否有微任务microtask(promise),如果有那就优先执行微任务,如果没有,在去查找宏任务macrotask(setTimeout、setInterval)进行执行

  2. 众所周知 JS 是⻔⾮阻塞单线程语⾔,因为在最初 JS 就是为了和浏览器交互⽽诞⽣的。如果 JS 是⻔多线程的语⾔话,我们在多个线程中处理 DOM 就可能会发⽣问题(⼀个线程中新加节点,另⼀个线程中删除节点),当然可以引⼊读写锁解决这个问题。

  3. JS 在执⾏的过程中会产⽣执⾏环境,这些执⾏环境会被顺序的加⼊到执⾏栈中。如果遇到异步的代码,会被挂起并加⼊到 Task (有多种 task ) 队列中。⼀旦执⾏栈为空,Event Loop 就会从 Task 队列中拿出需要执⾏的代码并放⼊执⾏栈中执⾏,所以本质上来说 JS 中的异步还是同步⾏为

    console.log('script start');
    setTimeout(function () {
        console.log('setTimeout');
    }, 0);
    console.log('script end');
    

以上代码虽然 setTimeout 延时为 0 ,其实还是异步。这是因为 HTML5 标准规定这个函数第⼆个参数不得⼩于 4 毫秒,不⾜会⾃动增加。所以 setTimeout 还是会在script end 之后打印。

JS 在执行的过程中会产生执行环境,这些执行环境会被顺序的加入到执行栈中。如果遇到异步的代码,会被挂起并加入到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为.

不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务( microtask )和 宏任务( macrotask )。在 ES6 规范中, microtask 称为 jobs, macrotask 称为task 。

console.log('1111');
setTimeout(function () {
    console.log('6666666');
}, 0);
new Promise((resolve) => {
    console.log('222222')
    resolve()
}).then(function () {
    console.log('44444444');
}).then(function () {
    console.log('555555555');
});
console.log('333333');

Event loop 顺序

  1. 执行同步代码,这属于宏任务
  2. 执行栈为空,查询是否有微任务需要执行
  3. 执行所有微任务
  4. 必要的话渲染 UI
  5. 然后开始下一轮 Event loop,执行宏任务中的异步代码

setImmediate,I/O,process.nextTick,MutationObserver

以下是使用 setImmediateI/Oprocess.nextTickMutationObserver 的示例代码:

// 使用 setImmediate 进行 I/O
console.log('在 setImmediate 之前');
setImmediate(() => {
  console.log('setImmediate 回调函数');
});
console.log('在 setImmediate 之后');

// 使用 process.nextTick 进行即时变异
console.log('在 process.nextTick 之前');
process.nextTick(() => {
  console.log('process.nextTick 回调函数');
});
console.log('在 process.nextTick 之后');

// 使用 MutationObserver 进行 DOM 变异监测
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    console.log('DOM 变异:', mutation);
  });
});

const target = document.querySelector('#target');
const config = { childList: true };
observer.observe(target, config);

// 修改 DOM 触发变异
console.log('在 DOM 变异之前');
target.innerHTML = '<p>新的内容</p>';
console.log('在 DOM 变异之后');

在这段代码中:

  1. 使用 setImmediate 进行 I/O 操作后的回调函数的调度。
  2. 使用 process.nextTick 进行即时变异,即在当前操作完成后立即执行的回调函数的调度。
  3. 使用 MutationObserver 监测和响应 DOM 的变化,例如 JavaScript 所进行的变异。

请注意,setImmediateprocess.nextTickNode.js 特定的功能,而 MutationObserver 是在浏览器环境中使用的,并且需要实际的 HTML 文档来观察 DOM 变异。

当我们希望监测 DOM 变化并在变化发生时执行相应的操作时,可以使用 MutationObserver。下面是一个使用 MutationObserver 的简单案例:

// 目标元素
const target = document.querySelector('#target');

// 创建 MutationObserver 实例
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    console.log('观察到 DOM 变化:', mutation);
  
    // 在这里可以执行相应的操作
    // 例如,可以使用 mutation.target 获取目标元素,对其进行相应的处理
  });
});

// 配置对象,定义我们希望观察的变化类型
const config = { childList: true, subtree: true, attributes: true };

// 开始观察目标元素的变化
observer.observe(target, config);

// 修改 DOM 触发变化
target.textContent = '新的文本内容';

// 停止观察变化
observer.disconnect();

在这个案例中:

  1. 我们首先通过 document.querySelector 方法选择了目标元素,这个目标元素可以是任何你希望观察变化的 DOM 元素。
  2. 我们创建了一个 MutationObserver 实例,传入了一个回调函数作为参数。当指定的变化类型发生时,这个回调函数将会被调用。
  3. 我们定义了一个配置对象,其中 childList: true 表示观察子元素的增加或删除,subtree: true 表示观察目标元素的所有后代元素,attributes: true 表示观察属性的变化。
  4. 通过调用 observer.observe(target, config) 方法,开始观察目标元素的变化。
  5. 我们修改了目标元素的文本内容,这会触发变化并导致观察者的回调函数被调用。
  6. 最后,我们可以通过调用 observer.disconnect() 方法停止观察变化。

在回调函数中,你可以根据变化的具体情况执行相应的操作,例如更新 UI、触发其他功能等。

process

Node.js 中的 process 全局对象提供了许多与当前 Node.js 进程有关的属性和方法。下面是一些常用的 process 对象的属性:

  1. process.argv:一个包含命令行参数的数组。第一个元素是 Node.js 的可执行文件路径,第二个元素是当前执行的 JavaScript 文件路径,后续元素是传递给脚本的命令行参数。

  2. process.env:一个包含当前进程环境变量的对象。可以使用它来获取或设置环境变量的值。

  3. process.cwd():返回当前工作目录的路径。

  4. process.pid:返回当前进程的标识符。

  5. process.platform:返回 Node.js 运行的操作系统平台。

  6. process.exit(code):以指定的退出码退出当前进程。

  7. process.uptime():返回 Node.js 进程的运行时间,以秒为单位。

  8. process.version:返回当前 Node.js 的版本号。

  9. process.arch:返回当前 Node.js 进程的处理器架构。

  10. process.title:获取或设置进程的名称。

这些只是 process 对象的一些常见属性,还有其他的一些属性和方法,可根据需要在代码中进一步探索和使用。可以通过查阅官方文档来获取更详细的信息:Node.js process 文档

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值