图文结合带你搞懂Nodejs中的事件循环

本篇文章通过图文结合的形式来带大家搞懂nodejs中的事件循环,希望对大家有所帮助!

图文结合带你搞懂Nodejs中的事件循环

以下全文7000字,请在你思路清晰、精力充沛的时刻观看。保证你理解后很长时间忘不掉。【推荐学习:《nodejs 教程》】

1.png

Node事件循环

Node底层使用的语言libuv,是一个c++语言。他用来操作底层的操作系统,封装了操作系统的接口。Node的事件循环也是用libuv来写的,所以Node生命周期和浏览器的还是有区别的。

因为Node和操作系统打交道,所以事件循环比较复杂,也有一些自己特有的API。
事件循环在不同的操作系统里有一些细微的差异。这将涉及到操作系统的知识,暂时不表。本次只介绍JS主线程中,Node的运作流程。Node的其他线程暂时也不扩展。

事件循环图

说好的一张图,也不卖关子。下边这张图搞清楚了,事件循环就学会了。

2.png

事件循环图

3.png

事件循环图-结构

为了让大家先有个大局观,先贴一张目录结构图在前边:

4.png

目录

接下来详细展开说说

主线程

5.png

主线程

上图中,几个色块的含义:

main:启动入口文件,运行主函数event loop:检查是否要进入事件循环检查其他线程里是否还有待处理事项检查其他任务是否还在进行中(比如计时器、文件读取操作等任务是否完成)有以上情况,进入事件循环,运行其他任务
事件循环的过程:沿着从timers到close callbacks这个流程,走一圈。到event loop看是否结束,没结束再走一圈。over:所有的事情都完毕,结束

事件循环 圈

6.png

事件循环 圈

图中灰色的圈跟操作系统有关系,不是本章解析重点。重点关注黄色、橙色的圈还有中间橘黄的方框。

我们把每一圈的事件循环叫做「一次循环」、又叫「一次轮询」、又叫「一次Tick」。

一次循环要经过六个阶段:

timers:计时器(setTimeout、setInterval等的回调函数存放在里边)

pending callback

idle prepare

poll:轮询队列(除timers、check之外的回调存放在这里)

check:检查阶段(使用 setImmediate 的回调会直接进入这个队列)

close callbacks

7.png

本次我们只关注上边标红的三个重点。

工作原理

每一个阶段都会维护一个事件队列。可以把每一个圈想象成一个事件队列。这就和浏览器不一样了,浏览器最多两个队列(宏队列、微队列)。但是在node里边有六个队列到达一个队列后,检查队列内是否有任务(也就是看下是否有回调函数)需要执行。如果有,就依次执行,直到全部执行完毕、清空队列。如果没有任务,进入下一个队列去检查。直到所有队列检查一遍,算一个轮询。其中,timerspending callbackidle prepare等执行完毕后,到达poll队列。

timers队列的工作原理

timers并非真正意义上的队列,他内部存放的是计时器。
每次到达这个队列,会检查计时器线程内的所有计时器,计时器线程内部多个计时器按照时间顺序排序。

检查过程:将每一个计时器按顺序分别计算一遍,计算该计时器开始计时的时间到当前时间是否满足计时器的间隔参数设定(比如1000ms,计算计时器开始计时到现在是否有1m)。当某个计时器检查通过,则执行其回调函数。

poll队列的运作方式

如果poll中有回调函数需要执行,依次执行回调,直到清空队列。如果poll中没有回调函数需要执行,已经是空队列了。则会在这里等待,等待其他队列中出现回调,如果其他队列中出现回调,则从poll向下到over,结束该阶段,进入下一阶段。如果其他队列也都没有回调,则持续在poll队列等待,直到任何一个队列出现回调后再进行工作。(是个小懒虫的处事方式)

举例梳理事件流程

setTimeout(() => {  console.log('object');}, 5000)console.log('node');

以上代码的事件流程梳理

进入主线程,执行setTimeout(),回调函数作为异步任务被放入异步队列timers队列中,暂时不执行。继续向下,执行定时器后边的console,打印“node”。判断是否有事件循环。是,走一圈轮询:从timers – pending callback – idle prepare……到poll队列停下循环并等待。由于这时候没到5秒,timers队列无任务,所以一直在poll队列卡着,同时轮询检查其他队列是否有任务。等5秒到达,setTimeout的回调塞到timers内,例行轮询检查到timers队列有任务,则向下走,经过check、close callbacks后到达timers。将timers队列清空。继续轮询到poll等待,询问是否还需要event loop,不需要,则到达over结束。

要理解这个问题,看下边的代码及流程解析:

setTimeout(function t1() {  console.log('setTimeout');}, 5000)console.log('node 生命周期');const http = require('http')const server = http.createServer(function h1() {  console.log('请求回调');});server.listen(8080)

代码分析如下:

照旧,先执行主线程,打印“node 生命周期”、引入http后创建http服务。然后event loop检查是否有异步任务,检查发现有定时器任务和请求任务。所以进入事件循环。

六个队列都没任务,则在poll队列等待。如下图:

8.png

过了五秒,timers中有了任务,则流程从poll放行向下,经过check和close callbacks队列后,到达event loop。event loop检查是否有异步任务,检查发现有定时器任务和请求任务。所以再次进入事件循环。

到达timers队列,发现有回调函数任务,则依次执行回调,清空timers队列(当然这里只有一个5秒到达后的回调,所以直接执行完了即可),打印出“setTimeout”。如下图

9.png

清空timers队列后,轮询继续向下到达poll队列,由于poll队列现在是空队列,所以在这里等待。后来,假设用户请求发来了,h1回调函数被放到poll队列。于是poll中有回调函数需要执行,依次执行回调,直到清空poll队列。

poll队列清空,此时poll队列是空队列,继续等待。

10.png

由于node线程一直holding在poll队列,等很长一段时间还是没有任务来临时,会自动断开等待(不自信表现),向下执行轮询流程,经过check、close callbacks后到达event loop到了event loop后,检查是否有异步任务,检查发现有请求任务。(此时定时器任务已经执行完毕,所以没有了),则继续再次进入事件循环。到达poll队列,再次holding……再等很长时间没有任务来临,自动断开到even loop(再补充一点无任务的循环情况)再次回到poll队列挂起无限循环……

梳理事件循环流程图:

注意:下图中的“是否有任务”的说法表示“是否有本队列的任务”。

11.png

event loop流程梳理

再用一个典型的例子验证下流程:

const startTime = new Date();setTimeout(function f1() {  console.log('setTimeout', new Date(), new Date() - startTime);}, 200)console.log('node 生命周期', startTime);const fs = require('fs')fs.readFile('./poll.js', 'utf-8', function fsFunc(err, data) {  const fsTime = new Date()  console.log('fs', fsTime);  while (new Date() - fsTime < 300) {  }  console.log('结束死循环', new Date());});

连续运行三遍,打印结果如下:

12.png

执行流程解析:

执行全局上下文,打印「node 生命周期 + 时间」

询问是否有event loop

有,进入timers队列,检查没有计时器(cpu处理速度可以,这时还没到200ms)

轮询进入到poll,读文件还没读完(比如此时才用了20ms),因此poll队列是空的,也没有任务回调

在poll队列等待……不断轮询看有没有回调

文件读完,poll队列有了fsFunc回调函数,并且被执行,输出「fs + 时间」

在while死循环那里卡300毫秒,

死循环卡到200ms的时候,f1回调进入timers队列。但此时poll队列很忙,占用了线程,不会向下执行。

直到300ms后poll队列清空,输出「结束死循环 + 时间」

event loop赶紧向下走

再来一轮到timers,执行timers队列里的f1回调。于是看到「setTimeout + 时间」

timers队列清空,回到poll队列,没有任务,等待一会。

等待时间够长后,向下回到event loop。

event loop检查没有其他异步任务了,结束线程,整个程序over退出。

check 阶段

检查阶段(使用 setImmediate 的回调会直接进入这个队列)

check队列的实际工作原理

真正的队列,里边扔的就是待执行的回调函数的集合。类似[fn,fn]这种形式的。
每次到达check这个队列后,立即按顺序执行回调函数即可【类似于[fn1,fn2].forEach((fn)=>fn())的感觉】

所以说,setImmediate不是一个计时器的概念。

如果你去面试,涉及到Node环节,可能会遇到下边这个问题:setImmediate和setTimeout(0)谁更快。

setImmediate() 与 setTimeout(0) 的对比

setImmediate的回调是异步的,和setTimeout回调性质一致。setImmediate回调在check队列,setTimeout回调在timers队列(概念意义,实际在计时器线程,只是setTimeout在timers队列做检查调用而已。详细看timers的工作原理)。setImmediate函数调用后,回调函数会立即push到check队列,并在下次eventloop时被执行。setTimeout函数调用后,计时器线程增加一个定时器任务,下次eventloop时会在timers阶段里检查判断定时器任务是否到达时间,到了则执行回调函数。综上,setImmediate的运算速度比setTimeout(0)的要快,因为setTimeout还需要开计时器线程,并增加计算的开销。

二者的效果差不多。但是执行顺序不定

观察以下代码:

华文笔杆 华文笔杆

写材料用华文,华文笔杆帮你搞定公文写作

华文笔杆 491 查看详情 华文笔杆

setTimeout(() => {  console.log('setTimeout');}, 0);setImmediate(() => {  console.log('setImmediate');});

多次反复运行,执行效果如下:

13.png

顺序不定

可以看到多次运行,两句console.log打印的顺序不定。
这是因为setTimeout的间隔数最小填1,虽然下边代码填了0。但实际计算机执行当1ms算。(这里注意和浏览器的计时器区分。在浏览器中,setInterval的最小间隔数为10ms,小于10ms则会被设置为10;设备供电状态下,间隔最小为16.6ms。)

以上代码,主线程运行的时候,setTimeout函数调用,计时器线程增加一个定时器任务。setImmediate函数调用后,其回调函数立即push到check队列。主线程执行完毕。

eventloop判断时,发现timers和check队列有内容,进入异步轮询:

第一种情况:等到了timers里这段时间,可能还没有1ms的时间,定时器任务间隔时间的条件不成立所以timers里还没有回调函数。继续向下到了check队列里,这时候setImmediate的回调函数早已等候多时,直接执行。而再下次eventloop到达timers队列,定时器也早已成熟,才会执行setTimeout的回调任务。于是顺序就是「setImmediate -> setTimeout」。

第二种情况:但也有可能到了timers阶段时,超过了1ms。于是计算定时器条件成立,setTimeout的回调函数被直接执行。eventloop再向下到达check队列执行setImmediate的回调。最终顺序就是「setTimeout -> setImmediate」了。

所以,只比较这两个函数的情况下,二者的执行顺序最终结果取决于当下计算机的运行环境以及运行速度。

二者时间差距的对比代码

------------------setTimeout测试:-------------------let i = 0;console.time('setTimeout');function test() {  if (i < 1000) {    setTimeout(test, 0)    i++  } else {    console.timeEnd('setTimeout');  }}test();------------------setImmediate测试:-------------------let i = 0;console.time('setImmediate');function test() {  if (i < 1000) {    setImmediate(test)    i++  } else {    console.timeEnd('setImmediate');  }}test();

运行观察时间差距:

14.png

setTimeout与setImmediate时间差距

可见setTimeout远比setImmediate耗时多得多
这是因为setTimeout不仅有主代码执行的时间消耗。还有在timers队列里,对于计时器线程中各个定时任务的计算时间。

结合poll队列的面试题(考察timers、poll和check的执行顺序)

如果你看懂了上边的事件循环图,下边这道题难不倒你!

// 说说下边代码的执行顺序,先打印哪个?const fs = require('fs')fs.readFile('./poll.js', () => {  setTimeout(() => console.log('setTimeout'), 0)  setImmediate(() => console.log('setImmediate'))})

上边这种代码逻辑,不管执行多少次,肯定都是先执行setImmediate。

15.png

先执行setImmediate

因为fs各个函数的回调是放在poll队列的。当程序holding在poll队列后,出现回调立即执行。
回调内执行setTimeout和setImmediate的函数后,check队列立即增加了回调。
回调执行完毕,轮询检查其他队列有内容,程序结束poll队列的holding向下执行。
check是poll阶段的紧接着的下一个。所以在向下的过程中,先执行check阶段内的回调,也就是先打印setImmediate。
到下一轮循环,到达timers队列,检查setTimeout计时器符合条件,则定时器回调被执行。

nextTick 与 Promise

说完宏任务,接下来说下微任务

二者都是「微队列」,执行异步微任务。二者不是事件循环的一部分,程序也不会开启额外的线程去处理相关任务。(理解:promise里发网络请求,那是网络请求开的网络线程,跟Promise这个微任务没关系)微队列设立的目的就是让一些任务「马上」、「立即」优先执行。nextTick与Promise比较,nextTick的级别更高。

nextTick表现形式

process.nextTick(() => {})

Promise表现形式

Promise.resolve().then(() => {})

如何参与事件循环?

事件循环中,每执行一个回调前,先按序清空一次nextTick和promise。

// 先思考下列代码的执行顺序setImmediate(() => {  console.log('setImmediate');});process.nextTick(() => {  console.log('nextTick 1');  process.nextTick(() => {    console.log('nextTick 2');  })})console.log('global');Promise.resolve().then(() => {  console.log('promise 1');  process.nextTick(() => {    console.log('nextTick in promise');  })})

最终顺序:

global

nextTick 1

nextTick 2

promise 1

nextTick in promise

setImmediate

两个问题:

基于上边的说法,有两个问题待思考和解决:

每走一个异步宏任务队列就查一遍nextTick和promise?还是每执行完 宏任务队列里的一个回调函数就查一遍呢?

如果在poll的holding阶段,插入一个nextTick或者Promise的回调,会立即停止poll队列的holding去执行回调吗?

16.gif

上边两个问题,看下边代码的说法

setTimeout(() => {  console.log('setTimeout 100');  setTimeout(() => {    console.log('setTimeout 100 - 0');    process.nextTick(() => {      console.log('nextTick in setTimeout 100 - 0');    })  }, 0)  setImmediate(() => {    console.log('setImmediate in setTimeout 100');    process.nextTick(() => {      console.log('nextTick in setImmediate in setTimeout 100');    })  });  process.nextTick(() => {    console.log('nextTick in setTimeout100');  })  Promise.resolve().then(() => {    console.log('promise in setTimeout100');  })}, 100)const fs = require('fs')fs.readFile('./1.poll.js', () => {  console.log('poll 1');  process.nextTick(() => {    console.log('nextTick in poll ======');  })})setTimeout(() => {  console.log('setTimeout 0');  process.nextTick(() => {    console.log('nextTick in setTimeout');  })}, 0)setTimeout(() => {  console.log('setTimeout 1');  Promise.resolve().then(() => {    console.log('promise in setTimeout1');  })  process.nextTick(() => {    console.log('nextTick in setTimeout1');  })}, 1)setImmediate(() => {  console.log('setImmediate');  process.nextTick(() => {    console.log('nextTick in setImmediate');  })});process.nextTick(() => {  console.log('nextTick 1');  process.nextTick(() => {    console.log('nextTick 2');  })})console.log('global ------');Promise.resolve().then(() => {  console.log('promise 1');  process.nextTick(() => {    console.log('nextTick in promise');  })})/** 执行顺序如下global ------nextTick 1nextTick 2promise 1nextTick in promisesetTimeout 0 // 解释问题1. 没有上边的nextTick和promise,setTimeout和setImmediate的顺序不一定,有了以后肯定是0先开始。// 可见,执行一个队列之前,就先检查并执行了nextTick和promise微队列nextTick in setTimeoutsetTimeout 1nextTick in setTimeout1promise in setTimeout1setImmediatenextTick in setImmediatepoll 1nextTick in poll ======setTimeout 100nextTick in setTimeout100promise in setTimeout100setImmediate in setTimeout 100nextTick in setImmediate in setTimeout 100setTimeout 100 - 0nextTick in setTimeout 100 - 0 */

以上代码执行多次,顺序不变,setTimeout和setImmediate的顺序都没变。

执行顺序及具体原因说明如下:

global :主线程同步任务,率先执行没毛病

nextTick 1:执行异步宏任务之前,清空异步微任务,nextTick优先级高,先行一步

nextTick 2:执行完上边这句代码,又一个nextTick微任务,立即率先执行

promise 1:执行异步宏任务之前,清空异步微任务,Promise的优先级低,所以在nextTick完了以后立即执行

nextTick in promise:清空Promise队列的过程中,遇到nextTick微任务,立即执行、清空

setTimeout 0: 解释第一个问题. 没有上边的nextTick和promise,只有setTimeout和setImmediate时他俩的执行顺序不一定。有了以后肯定是0先开始。可见,执行一个宏队列之前,就先按顺序检查并执行了nextTick和promise微队列。等微队列全部执行完毕,setTimeout(0)的时机也成熟了,就被执行。

nextTick in setTimeout:执行完上边这句代码,又一个nextTick微任务,立即率先执行 【这种回调函数里的微任务,我不能确定是紧随同步任务执行的;还是放到微任务队列,等下一个宏任务执行前再清空的他们。但是顺序看上去和立即执行他们一样。不过我比较倾向于是后者:先放到微任务队列等待,下一个宏任务执行前清空他们。】

setTimeout 1:因为执行微任务耗费时间,导致此时timers里判断两个0和1的setTimeout计时器已经结束,所以两个setTimeout回调都已加入队列并被执行

nextTick in setTimeout1:执行完上边这句代码,又一个nextTick微任务,立即率先执行 【可能是下一个宏任务前清空微任务】

promise in setTimeout1:执行完上边这句代码,又一个Promise微任务,立即紧随执行 【可能是下一个宏任务前清空微任务】

setImmediate:poll队列回调时机未到,先行向下到check队列,清空队列,立即执行setImmediate回调

nextTick in setImmediate:执行完上边这句代码,又一个nextTick微任务,立即率先执行 【可能是下一个宏任务前清空微任务】

poll 1:poll队列实际成熟,回调触发,同步任务执行。

nextTick in poll :执行完上边这句代码,又一个nextTick微任务,立即率先执行 【可能是下一个宏任务前清空微任务】

setTimeout 100:定时器任务到达时间,执行回调。并在回调里往微任务推入了nextTick、Promise,往宏任务的check里推入了setImmediate的回调。并且也开启了计时器线程,往timers里增加了下一轮回调的可能。

nextTick in setTimeout100:宏任务向下前,率先执行定时器回调内新增的微任务-nextTick 【这里就能确定了,是下一个宏任务前清空微任务的流程】

promise in setTimeout100:紧接着执行定时器回调内新增的微任务-Promise 【清空完nextTick清空Promise的顺序】

setImmediate in setTimeout 100:这次setImmediate比setTimeout(0)先执行的原因是:流程从timers向后走到check队列,已经有了setImmediate的回调,立即执行。

nextTick in setImmediate in setTimeout 100:执行完上边这句代码,又一个nextTick微任务,下一个宏任务前率先清空微任务

setTimeout 100 - 0:轮询又一次回到timers,执行100-0的回调。

nextTick in setTimeout 100 - 0:执行完上边这句代码,又一个nextTick微任务,下一个宏任务前率先清空微任务。

扩展:为什么有了setImmediate还要有nextTick和Promise?

一开始设计的时候,setImmediate充当了微队列的作用(虽然他不是)。设计者希望执行完poll后立即执行setImmediate(当然现在也确实是这么表现的)。所以起的名字叫Immediate,表示立即的意思。但是后来问题是,poll里可能有N个任务连续执行,在执行期间想要执行setImmediate是不可能的。因为poll队列不停,流程不向下执行。

于是出现nextTick,真正的微队列概念。但此时,immediate的名字被占用了,所以名字叫nextTick(下一瞬间)。事件循环期间,执行任何一个队列之前,都要检查他是否被清空。其次是Promise。

面试题

最后,检验学习成果的面试题来了

async function async1() {  console.log('async start');  await async2();  console.log('async end');}async function async2(){  console.log('async2');}console.log('script start');setTimeout(() => {  console.log('setTimeout 0');}, 0)setTimeout(() => {  console.log('setTimeout 3');}, 3)setImmediate(() => {  console.log('setImmediate');})process.nextTick(() => {  console.log('nextTick');})async1();new Promise((res) => {  console.log('promise1');  res();  console.log('promise2');}).then(() => {  console.log('promise 3');});console.log('script end');// 答案如下// -// -// -// -// -// -// -// -// -// -// -// -/**script startasync startasync2promise1promise2script endnextTickasync endpromise 3// 后边这仨的运行顺序就是验证你电脑运算速度的时候了。速度最好(执行上边的同步代码 + 微任务 + 计时器运算用了不到0ms):setImmediatesetTimeout 0setTimeout 3速度中等(执行上边的同步代码 + 微任务 + 计时器运算用了0~3ms以上):setTimeout 0setImmediatesetTimeout 3速度较差(执行上边的同步代码 + 微任务 + 计时器运算用了3ms以上):setTimeout 0setTimeout 3setImmediate*/

思维脑图 – Node生命周期核心阶段

17.png

18.gif

更多编程相关知识,请访问:编程视频!!

以上就是图文结合带你搞懂Nodejs中的事件循环的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/560599.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月10日 00:47:41
下一篇 2025年11月10日 00:51:48

相关推荐

  • 配置 Tailwind CSS:初始化指南 |设置 Tailwind CSS:初始化指南

    简介 |简介意大利语:本文有意大利语和英语版本。向下滚动查看英文版本。英语:本文有意大利语和英语版本。向下滚动查看英文版本。 意大利语版 如何开始使用 tailwind css:项目完整指南 简介 在项目中配置 tailwind css 第一次似乎令人畏惧,特别是对于像我这样第一次尝试这个库的人来说…

    2025年12月24日
    000
  • 如何设置独立 CLI:在 Shopify 中使用 Tailwind CSS,而不使用 Nodejs

    依赖关系 Shopify CLI:一种命令行界面工具,可帮助您开发和管理 Shopify 主题。TailwindCSS:实用程序优先的 CSS 框架,用于快速构建自定义设计。 设置 我们使用 Tailwind 作为独立的 CLI 工具。更多信息可以参考官方指南。 注意:如果您在配备 Intel 处理…

    2025年12月24日
    000
  • 谷歌怎么下载html5_HTML5无需下载浏览器直接渲染运行页面文件【说明】

    HTML5不是需下载的软件,而是浏览器原生标准;Chrome默认支持,可通过file://协议直接打开本地.html文件,或用http-server启动本地服务器以支持完整API功能。 如果您已编写好HTML5页面文件,但误以为需要“下载HTML5”才能运行,则需明确:HTML5不是可下载的独立软件…

    2025年12月23日
    000
  • 手机编程html5工具_移动端代码编辑器推荐【指南】

    推荐五款移动端HTML5编辑器:Acode Editor支持一键预览;DroidEdit Pro可FTP/SFTP远程编辑;Codeanywhere提供云端IDE与Git集成;SpckEditor专注极简单页开发;Termux组合方案实现命令行本地服务。 如果您希望在手机上直接编写、调试和预览 HT…

    2025年12月23日
    000
  • Linux polybar状态栏,HTML+CSS加载进度实时!

    可通过 Bash 脚本在 Polybar 中模拟 HTML+CSS 风格进度条,利用 %{F#color} 标记和块字符 ▮ 动态显示已完成与未完成部分,结合实时任务进度输出格式化文本。 如果您希望在 Linux 的 Polybar 状态栏中显示一个基于 HTML+CSS 风格的加载进度条,并实时反…

    2025年12月23日
    000
  • Node.js Puppeteer爬虫的部署与自动化运行指南

    本教程详细指导如何部署基于node.js和puppeteer的网络爬虫,并实现其自动化定时执行。文章区分了前端静态网站与后端node.js脚本的部署策略,重点介绍了在windows环境下使用任务计划程序(task scheduler)进行定时任务配置的方法,同时提及了cors问题产生的原因及解决方案…

    2025年12月23日
    000
  • Linux Debian用Gulp自动化,CSS编译HTML零等待!

    首先安装Node.js与npm,再初始化项目并安装Gulp及插件,接着配置gulpfile.js定义Sass编译与浏览器同步任务,最后通过gulp命令启动自动化流程,实现CSS即时编译与HTML实时更新。 如果您希望在Linux Debian系统中通过Gulp实现自动化工作流,以达到CSS即时编译、…

    2025年12月23日
    000
  • Node.js爬虫的服务器端部署与定时任务配置指南

    本文旨在指导开发者如何部署基于%ignore_a_1%的puppeteer网络爬虫,并实现其定时自动化运行。针对本地开发环境,文章详细介绍了利用windows任务计划程序配置定时任务的步骤,确保node.js脚本能按预设时间自动执行,更新数据。同时,文章也探讨了生产环境下的部署思路,强调了客户端与服…

    2025年12月23日
    000
  • Node.js爬虫的部署、调度与静态网站数据集成指南

    本教程详细阐述如何部署和自动化运行node.js网络爬虫,实现定时数据抓取并更新静态网站内容。我们将探讨node.js脚本的服务器端运行机制、windows任务计划程序等调度工具的配置,以及爬取数据与静态html页面集成的策略,旨在帮助您构建高效且自动化的数据更新流程。 1. 理解Node.js爬虫…

    2025年12月23日
    000
  • 部署与自动化运行Node.js网络爬虫:使用Windows任务计划程序

    本文将指导您如何部署一个基于node.js和puppeteer的网络爬虫,并利用windows任务计划程序实现其每日定时自动运行。我们将深入探讨服务器端脚本与静态网页的区别,提供详细的步骤配置任务计划,并讨论在自动化过程中需要注意的关键事项,如资源管理、错误处理及跨平台部署思路。 理解Node.js…

    2025年12月23日
    000
  • 部署与调度Node.js爬虫:从本地执行到云端集成

    本教程详细指导如何部署和调度一个基于node.js的网页爬虫,使其能够每日自动运行并将其数据提供给前端应用。文章将区分客户端与服务器端javascript的运行环境,介绍本地任务调度方法,并探讨将爬虫集成到在线服务以实现数据共享的策略,同时涵盖数据持久化、cors处理及部署最佳实践。 1. 理解No…

    2025年12月23日
    000
  • nodejs如何打开html_Node.js环境中HTML文件打开方法

    如果您在Node.js环境中需要打开或提供HTML文件的访问,通常意味着您希望启动一个本地服务器来渲染并展示HTML页面。以下是实现该功能的具体方法: 一、使用内置http模块创建服务器 通过Node.js的内置http模块可以快速搭建一个简易服务器,用于读取并返回HTML文件内容给客户端浏览器。 …

    2025年12月23日
    000
  • WSL2里写HTML+CSS,Windows秒变Linux开发机!

    使用WSL2可在Windows中高效进行Linux环境下的HTML与CSS开发。首先启用WSL2并安装Ubuntu 22.04,确保运行版本为2;接着安装Visual Studio Code及Remote – WSL插件,将项目存于Linux文件系统以实现编辑同步;通过Python内置服…

    2025年12月23日
    000
  • Windows WSL2中Linux环境运行HTML+CSS开发服务器

    在WSL2中配置Linux环境进行HTML+CSS开发,首先启用WSL2并安装Ubuntu等发行版,运行wsl –install后重启并设置用户;接着更新系统包sudo apt update && sudo apt upgrade;推荐使用Python3内置服务器,在项目…

    2025年12月23日
    000
  • Linux用stylelint实时校验CSS是否符合HTML规范

    Stylelint用于校验CSS书写规范,可通过配置文件和编辑器插件在Linux中实现实时检查,并结合chokidar监听文件变化,确保CSS代码质量并与HTML协同工作。 Stylelint 是一个强大的 CSS 代码检查工具,但它主要用于校验 CSS 的书写规范(如格式、可维护性、错误预防等),…

    2025年12月23日
    000
  • Windows用Prettier同时格式化HTML和CSS代码

    答案:在Windows中使用Prettier格式化HTML和CSS需先安装Node.js,再通过npm安装Prettier,可全局或项目本地安装,推荐配合VS Code插件实现保存自动格式化,注意文件扩展名正确以确保语言识别。 在 Windows 系统中使用 Prettier 格式化 HTML 和 …

    2025年12月23日
    000
  • 如何在Atom中集成HTML预处理器Sass的详细教程

    首先安装Node.js和Dart Sass,再在Atom中安装atom-sass等插件,配置文件结构与编译规则,通过插件或命令行监听实现.scss文件自动编译为CSS,并在HTML中引入生成的CSS文件,从而提升开发效率。 要在Atom中集成Sass预处理器,让HTML开发更高效,关键在于安装合适的…

    2025年12月23日
    000
  • Linux Ubuntu用BrowserSync同步HTML与CSS多设备

    首先安装Node.js和npm,再全局安装BrowserSync,进入项目目录启动服务器并监听HTML与CSS文件,通过局域网IP在多设备访问,修改代码后页面自动同步刷新,支持CSS热替换,需确保设备同Wi-Fi且端口开放。 要在Linux Ubuntu系统中使用BrowserSync实现HTML与…

    2025年12月23日
    000
  • nodejs如何添加html_Node.js服务端HTML渲染与响应方法

    Node.js中返回HTML可通过原生HTTP模块直接发送字符串或使用模板引擎动态渲染。直接返回时需设置Content-Type为text/html并用res.end()发送HTML内容;对于动态数据,可结合EJS等模板引擎读取模板文件并渲染数据后返回;更推荐在中大型项目中使用Express框架,配…

    2025年12月23日
    000
  • termux如何运行html_Termux终端中HTML文件运行与预览方法

    推荐使用Python启动本地服务器预览HTML文件:进入项目目录后运行python -m http.server 8000,再通过手机浏览器访问http://localhost:8000即可查看页面效果。 在Termux中运行和预览HTML文件,虽然不能像桌面浏览器那样直接双击打开,但通过简单的工具…

    2025年12月23日
    000

发表回复

登录后才能评论
关注微信