Node.js-0003-CentOS 7.9 安装 Node.js 18.x-02-编译 make
在前端应用部署的编译需求下,Node.js环境不可或缺。源码为了满足这个需求,编译本文将介绍如何在CentOS 7.9系统上安装Node.js .x版本,源码特别是编译elasticsearch源码设置通过编译make命令实现。
这个教程系列是源码基于之前的文章,包括了对Node.js .x的编译安装和gcc编译的准备。首先,源码我们从下载make-4.4版本开始,编译这是源码构建过程中不可或缺的工具。
下载完成后,编译进行配置以确保其与系统环境兼容,源码配置过程顺利完成后,编译我们继续进行编译步骤,源码源码网站git这一步骤的完成预示着make工具即将被成功构建。
编译成功后,紧接着是安装阶段,这一步会将编译好的make工具整合到系统中,为后续Node.js的安装提供支持。最终,我们将替换掉系统中原本的make版本,从3.升级到4.4,以提升系统的性能和兼容性。
在完成所有这些步骤后,你将拥有一套完整的Node.js .x环境,可以顺利进行前端应用的开发和部署。而这一切,都在瓜达卢佩山脉国家公园的kugo源码手机宁静背景中进行,美国瓜达卢佩山脉国家公园的壮丽景色仿佛为这个技术实践增添了别样的韵味。
nodejs原理&源码赏析(7)Node.js中的事件循环,定时器和process.nextTick
事件循环是Node.js的核心机制,确保了其非阻塞I/O模型的实现。尽管JavaScript在Node.js中是单线程运行的,它却能利用系统内核的多线程特性处理并发任务。Node.js在开始执行时初始化事件循环,处理脚本文件或REPL环境中的异步调用。事件循环通过检查异步I/O、定时器和process.nextTick调用,然后进入各个阶段,处理回调函数。每个阶段维护一个先进先出的回调队列,处理与阶段相关操作后执行队列中的彩带公式源码回调,直至队列为空或达到最大函数执行数量。系统操作回调、定时器和处理关闭回调的阶段各有功能。setImmediate()与setTimeout()相似,但执行顺序受调用上下文影响,setImmediate()在I/O周期中通常优先执行。process.nextTick()则在当前操作执行后立即执行回调,不受事件循环阶段限制,但需谨慎使用以防阻塞事件循环。
nodejsç¼è¯ï¼
nodejsç¼è¯åjsæ件ååç¼
Node.jsæ¯ä¸ä¸ªåºäºChromeV8å¼æçJavaScriptè¿è¡ç¯å¢ã
Nodeä¸javaScriptçåºå«å¨äºï¼javaScriptç顶å±å¯¹è±¡æ¯window,ènodeæ¯global
//è¿é使ç¨çvar声æçåéä¸æ¯å ¨å±çï¼æ¯å½å模åä¸çï¼ç¨global声æç表示æ¯å ¨å±ç
vars=;
global.s=;
//è¿é访é®å°çsæ¯varçå½ç
console.log(s);//
//è¿é访é®å°çææ¯å ¨å±åé
console.log(global.s);//
模åï¼å¨nodeä¸ï¼æ件å模åæ¯ä¸ä¸å¯¹åºçï¼ä¹å°±æ¯ä¸ä¸ªæ件就æ¯ä¸ä¸ªæ¨¡åï¼æ¯ä¸ªæ¨¡åé½æèªå·±çä½ç¨åï¼æ们éè¿varç³æçåé并éå ¨å±èæ¯è¯¥æ¨¡åä½ç¨åä¸çã
ï¼2ï¼module模å
1ãæ件æ¥æ¾
1ï¼é¦å æç §å è½½ç模åçæ件å称è¿è¡æ¥æ¾ï¼å¦æ没ææ¾å°ï¼åä¼å¸¦ä¸.jsã.jsonæ.nodeæå±åå¨å è½½
2ï¼ä»¥'/'为åç¼ç模åæ¯æ件çç»å¯¹è·¯å¾ãä¾å¦ï¼require('/home/marco/foo.js')ä¼å è½½/home/marco/foo.jsæ件ã
3ï¼ä»¥'./'为åç¼ç模åæ¯ç¸å¯¹äºè°ç¨require()çæ件çãä¹å°±æ¯è¯´ï¼circle.jså¿ é¡»åfoo.jså¨åä¸ç®å½ä¸ä»¥ä¾¿äºrequire('./circle')æ¾å°å®ã
4ï¼å½æ²¡æ以'/'ã'./'æ'../'å¼å¤´æ¥è¡¨ç¤ºæ件æ¶ï¼è¿ä¸ªæ¨¡åå¿ é¡»æ¯ä¸ä¸ªæ ¸å¿æ¨¡åæå è½½èªnode_modulesç®å½ã
5ï¼å¦æç»å®çè·¯å¾ä¸åå¨ï¼årequire()ä¼æåºä¸ä¸ªcodeå±æ§ä¸º'MODULE_NOT_FOUND'çErrorã
2ãmoduleä½ç¨å
å¨ä¸ä¸ªæ¨¡åä¸éè¿varå®ä¹çåéï¼å ¶ä½ç¨åèå´æ¯å½å模åï¼å¤é¨ä¸è½å¤ç´æ¥ç访é®ï¼å¦ææ们æ³ä¸ä¸ªæ¨¡åè½å¤è®¿é®å¦å¤ä¸ä¸ªæ¨¡åä¸å®ä¹çåéï¼å¯ä»¥æä¸ä¸ä¸¤ç§æ¹å¼ï¼
1ï¼æåéä½ä¸ºglobal对象çä¸ä¸ªå±æ§ï¼ä½è¿æ ·çåæ³æ¯ä¸æ¨èç
2ï¼ä½¿ç¨æ¨¡å对象moduleãmoduleä¿åæä¾åå½å模åæå ³çä¸äºä¿¡æ¯ã
å¨è¿ä¸ªmodule对象ä¸æä¸ä¸ªå对象exports对象ï¼æ们å¯ä»¥éè¿è¿ä¸ªå¯¹è±¡æä¸ä¸ªæ¨¡åä¸çå±é¨åé对象è¿è¡æä¾è®¿é®ã
//è¿ä¸ªæ¹æ³çè¿åå¼ï¼å ¶å®å°±æ¯è¢«å 载模åä¸çmodule.exports
require('./.js');
3ã__dirnameï¼å½å模åçç®å½åã
ä¾åï¼å¨/Users/mjrç®å½ä¸è¿è¡nodeexample.jsï¼
console.log(__dirname);
//è¾åº:/Users/mjr
console.log(path.dirname(__filename));
//è¾åº:/Users/mjr
4ã__filenameï¼å½å模åçæ件åï¼å¤çåçç»å¯¹è·¯å¾ï¼ãå½å模åçç®å½åå¯ä»¥ä½¿ç¨__dirnameè·åã
å¨/Users/mjrç®å½ä¸è¿è¡nodeexample.jsï¼
console.log(__filename);
//è¾åº:/Users/mjr/example.js
console.log(__dirname);
//è¾åº:/Users/mjr
ï¼3ï¼processï¼è¿ç¨ï¼
process对象æ¯ä¸ä¸ªå ¨å±åéï¼æä¾Node.jsè¿ç¨çæå ³ä¿¡æ¯ä»¥åæ§å¶è¿ç¨ãå 为æ¯å ¨å±åéï¼æ以æ é使ç¨require()ã
1ãprocess.argv
è¿åè¿ç¨å¯å¨æ¶çå½ä»¤è¡åæ°ã第ä¸ä¸ªå ç´ æ¯process.execPathã第äºä¸ªå ç´ æ¯å½åæ§è¡çJavaScriptæ件çè·¯å¾ãå©ä½çå ç´ é½æ¯é¢å¤çå½ä»¤è¡åæ°ã
console.log(process.argv);
æå°ç»æï¼
2ãprocess.execPathè¿åå¯å¨è¿ç¨çå¯æ§è¡æ件çç»å¯¹è·¯å¾ã
3ãprocess.envè¿åç¨æ·çç¯å¢ä¿¡æ¯ã
å¨process.envä¸å¯ä»¥æ°å¢å±æ§ï¼
process.env.foo='bar';
console.log(process.env.foo);
å¯ä»¥éè¿deleteå é¤å±æ§ï¼
deleteprocess.env.foo;
console.log(process.env);
å¨Windowsä¸ï¼ç¯å¢åéä¸åºå大å°å
4ãprocess.pidå±æ§è¿åè¿ç¨çPIDã
5ãprocess.platformå±æ§è¿åå符串ï¼æ è¯Node.jsè¿ç¨è¿è¡å ¶ä¸çæä½ç³»ç»å¹³å°ã
6ãprocess.titleå±æ§ç¨äºè·åæ设置å½åè¿ç¨å¨pså½ä»¤ä¸æ¾ç¤ºçè¿ç¨åå
7ãprocess.uptime()æ¹æ³è¿åå½åNode.jsè¿ç¨è¿è¡æ¶é´ç§é¿
注æ:该è¿åå¼å å«ç§çåæ°ã使ç¨Math.floor()æ¥å¾å°æ´ç§éã
8ãprocess.versionså±æ§è¿åä¸ä¸ªå¯¹è±¡ï¼æ¤å¯¹è±¡ååºäºNode.jsåå ¶ä¾èµççæ¬ä¿¡æ¯ã
process.versions.modules表æäºå½åABIçæ¬ï¼æ¤çæ¬ä¼éçä¸ä¸ªC++APIååèå¢å ãNode.jsä¼æç»å 载模åï¼å¦æè¿äºæ¨¡å使ç¨ä¸ä¸ªä¸åABIçæ¬ç模åè¿è¡ç¼è¯ã
9ãprocess对象-è¾å ¥è¾åºæµ
vara;
varb;
process.stdout.write('请è¾å ¥açå¼:');
process.stdin.on('data',(chunk)={
if(!a){
a=Number(chunk);
process.stdout.write('请è¾å ¥bçå¼:');
}else{
b=Number(chunk);
process.stdout.write('a+bçå¼:'+(a+b));
process.exit();
}
});
ï¼4ï¼Bufferç¼å²å¨
Bufferç±»ï¼ä¸ä¸ªç¨äºæ´å¥½çæä½äºè¿å¶æ°æ®çç±»ï¼æ们å¨æä½æ件æè ç½ç»æ°æ®çæ¶åï¼å ¶å®æä½çå°±æ¯äºè¿å¶æ°æ®æµï¼Node为æ们æä¾äºä¸ä¸ªæ´å æ¹ä¾¿çå»æä½è¿ç§æ°æ®æµçç±»Buffer,ä»æ¯ä¸ä¸ªå ¨å±çç±»
1ãå¦ä½å建使ç¨buffer
Buffer.from(array)è¿åä¸ä¸ªBufferï¼å å«ä¼ å ¥çåèæ°ç»çæ·è´ã
Buffer.from(arrayBuffer[,byteOffset[,length]])è¿åä¸ä¸ªBufferï¼ä¸ä¼ å ¥çArrayBufferå ±äº«å åã
Buffer.from(buffer)è¿åä¸ä¸ªBufferï¼å å«ä¼ å ¥çBufferçå 容çæ·è´ã
Buffer.from(string[,encoding])è¿åä¸ä¸ªBufferï¼å å«ä¼ å ¥çå符串çæ·è´ã
Buffer.alloc(size[,fill[,encoding]])è¿åä¸ä¸ªæå®å¤§å°ä¸å·²åå§åçBufferã该æ¹æ³æ¯Buffer.allocUnsafe(size)æ ¢ï¼ä½è½ç¡®ä¿æ°å建çBufferä¸ä¼å å«æ§æ°æ®ã
Buffer.allocUnsafe(size)ä¸Buffer.allocUnsafeSlow(size)è¿åä¸ä¸ªæå®å¤§å°ä½æªåå§åçBufferãå 为Bufferæ¯æªåå§åçï¼å¯è½å å«æ§æ°æ®ã
//å建ä¸ä¸ªé¿åº¦ä¸ºãä¸ç¨å¡«å çBufferã
constbuf1=Buffer.alloc(,1);
//å建ä¸ä¸ªé¿åº¦ä¸ºãä¸æªåå§åçBufferã
//è¿ä¸ªæ¹æ³æ¯è°ç¨Buffer.alloc()æ´å¿«ï¼ä½è¿åçBufferå®ä¾å¯è½å å«æ§æ°æ®ï¼å æ¤éè¦ä½¿ç¨fill()æwrite()éåã
constbuf2=Buffer.allocUnsafe();
constbuf3=Buffer.from([1,2,3]);
constbuf4=Buffer.from('tést');
console.log(buf1);//Buffer
console.log(buf2);//Buffer
console.log(buf3);//Buffer
console.log(buf4);//Bufferc3a
2ãBuffer对象æä¾çtoStringãJSONç使ç¨
1ï¼buf.toString(encodingï¼startï¼end)
varbf=Buffer.from('miaov');
console.log(bf.toString('utf-8',1,4));//iaov
console.log(bf.toString('utf-8',0,5));//miaov
console.log(bf.toString('utf-8',0,6));//miaov
2ï¼buf.write(stringï¼offsetï¼lengthï¼encoding)
stringè¦åå ¥bufçå符串ã
offsetå¼å§åå ¥çå移éãé»è®¤0ï¼è¿éæçæ¯buffer对象çèµ·å§è¦åå ¥çä½ç½®ã
lengthè¦åå ¥çåèæ°ãé»è®¤ä¸ºbuf.length-offsetã
encodingstringçå符ç¼ç ãé»è®¤ä¸º'utf8'ã
è¿å:å·²åå ¥çåèæ°ã
varstr="miaovhello";
varbf=Buffer.from(str);
varbf2=Buffer.alloc(8);
//ä»0å¼å§åå ¥5个
bf2.write(str,0,5);
console.log(bf);
console.log(bf2);
3ï¼buf.toJSON()
constbuf=Buffer.from([0x1,0x2,0x3,0x4,0x5]);
constjson=JSON.stringify(buf);
console.log(json);
//è¾åº:{ "type":"Buffer","data":[1,2,3,4,5]}
3ãBufferä¸éææ¹æ³ç使ç¨
1ï¼Buffer.isEncoding(encoding)ï¼å¤ææ¯å¦æ¯Bufferæ¯æçå符ç¼ç ï¼æ¯åè¿åtrueï¼ä¸æ¯åè¿åfalse
console.log(Buffer.isEncoding('utf-8'));//true
2ï¼Buffer.isBuffer(obj)ï¼å¦æobjæ¯ä¸ä¸ªBufferï¼åè¿åtrueï¼å¦åè¿åfalseã
ï¼5ï¼fsï¼æ件系ç»ï¼
该模åæ¯æ ¸å¿æ¨¡åï¼éè¦ä½¿ç¨require('fs')å¯¼å ¥å使ç¨ï¼è¯¥æ¨¡å主è¦ç¨æ¥æä½æ件
1ãfs.open(path,flags,mode,callback)
pathï¼è¦æå¼çæ件çè·¯å¾ï¼
flagsï¼æå¼æ件çæ¹å¼è¯»/åï¼
modeï¼è®¾ç½®æ件ç模å¼è¯»/å/æ§è¡
callback(errï¼fd)ï¼æ件æå¼ä»¥åï¼å¨åè°å½æ°ä¸åç¸åºçå¤ç,åè°å½æ°ç两个åæ°ï¼
errï¼æ件æå¼å¤±è´¥çé误ä¿åå¨erréé¢ï¼å¦ææåerr为null
fdï¼è¢«æå¼æ件çæ è¯
varfs=require('fs');
fs.open('./test.txt','r',function(err,fd){
if(err){
console.log("æ件æå¼å¤±è´¥");
}else{
console.log("æ件æå¼æå");
}
});
2ãfs.openSync(path,flags,mode)ï¼è¿åæ件æ述符ã
varfs=require('fs');
console.log(fs.openSync('./test.txt','r'));//3
3ãfs.read(fd,buffer,offset,length,position,callback)
ä»fdæå®çæ件ä¸è¯»åæ°æ®ï¼
bufferæå®è¦åå ¥æ°æ®çbufferï¼
offsetæå®bufferä¸å¼å§åå ¥çå移éï¼
lengthæå®è¦è¯»åçåèæ°ï¼
positionæå®æ件ä¸å¼å§è¯»åçå移éãå¦æposition为nullï¼åä»æ件çå½åä½ç½®å¼å§è¯»åï¼
callbackæä¸ä¸ªåæ°(err,bytesRead,buffer)
示ä¾ï¼test.txtä¸çå¼ä¸º
fs.open('./test.txt','r',function(err,fd){
if(!err){
varbf=Buffer.alloc(5);
fs.read(fd,bf,0,5,0,function(){
console.log(bf.toString());//
})
}
});
4ãfs.write(fd,buffer,offset,length,position,callback)
å°bufferåå ¥å°fdæå®çæ件ã
offsetæå®bufferä¸è¦å¼å§è¢«åå ¥çå移éï¼lengthæå®è¦åå ¥çåèæ°ã
positionæå®æ件ä¸è¦å¼å§åå ¥çå移éãå¦ætypeofposition!=='number'ï¼åä»å½åä½ç½®å¼å§åå ¥ã
callbackæä¸ä¸ªåæ°(err,bytesWritten,buffer)ï¼å ¶ä¸bytesWrittenæå®bufferä¸å·²åå ¥æ件çåèæ°ã
varfs=require('fs');
fs.open('./test.txt','r+',function(err,fd){
if(!err){
varbf=Buffer.alloc(5);
fs.read(fd,bf,0,5,0,function(){
console.log(bf.toString());//
});
varbf=Buffer.from('testæ°æ®');
fs.write(fd,bf,0,,0);
fs.write(fd,'æµè¯æ°æ®2',,'utf-8');
}
});
fs.write(fd,string,position,encoding,callback)
å°stringåå ¥å°fdæå®çæ件ãå¦æstringä¸æ¯ä¸ä¸ªå符串ï¼åä¼å¼ºå¶è½¬æ¢æå符串ã
positionæå®æ件ä¸è¦å¼å§åå ¥çå移éãå¦ætypeofposition!=='number'ï¼åä»å½åä½ç½®å¼å§åå ¥ã
encodingæå®å符串çç¼ç ã
callbackæä¸ä¸ªåæ°(err,written,string)ï¼å ¶ä¸writtenæå®å符串ä¸å·²åå ¥æ件çåèæ°ãåå ¥çåèæ°ä¸å符串çå符æ°æ¯ä¸åçã
5ãfs.exists(path,callback)æ£æ¥æå®è·¯å¾çæ件æè ç®å½æ¯å¦åå¨
fs.appendFile(path,data,callback)ï¼å°æ°æ®è¿½å å°æ件ï¼å¦ææ件ä¸åå¨åå建æ件ã
//æ£æ¥æ件æ¯å¦åå¨
varfs=require('fs');
varfilename='./test2.txt';
fs.exists(filename,function(isExists){
if(!isExists){
fs.writeFile(filename,'miaov',function(err){
if(err){
console.log("æ件å建失败");
}else{
console.log("æ件å建æå");
}
});
}else{
fs.appendFile(filename,'-leo',function(err){
if(err){
console.log("æ件å 容追å 失败");
}else{
console.log("æ件å 容追å æå");
}
})
}
});
ï¼6ï¼å端项ç®èªå¨åæ建
1ãå建myProject项ç®æ件以å对åºçæ件夹
varprojectData={
'name':'myProject',
'fileData':[
{
'name':'css',
'type':'dir'
},{
'name':'js',
'type':'dir'
},{
'name':'images',
'type':'dir'
},{
'name':'index.html',
'type':'file',
'content':'html\n\thead\n\t\ttitletitle/title\n\t/head\n\tbody\n\t\th1Hello/h1\n\t/body\n/html'
}
]
};
varfs=require('fs');
if(projectData.name){
//å建项ç®æ件夹
fs.mkdirSync(projectData.name);
varfileData=projectData.fileData;
if(fileDatafileData.length){
fileData.forEach(function(file){
//æ件ææ件夹路å¾
file.path='./'+projectData.name+'/'+file.name;
//æ ¹æ®typeç±»åå建æ件ææ件夹
file.content=file.content||'';
switch(file.type){
case'dir':
fs.mkdirSync(file.path);
break;
case'file':
fs.writeFileSync(file.path,file.content);
break;
default:
break;
}
});
}
}
2ãèªå¨æå å¤ä¸ªæ件
varfs=require('fs');
varfiledir='./myProject/dist';
fs.exists(filedir,function(isExists){
if(!isExists){
fs.mkdirSync(filedir);
}
fs.watch(filedir,function(ev,file){
//åªè¦æä¸ä¸ªæ件åçäºååï¼æ们就éè¦å¯¹æ件夹ä¸çæææ件è¿è¡è¯»åãå并
fs.readdir(filedir,function(err,dataList){
vararr=[];
dataList.forEach(function(file){
if(file){
//statSyncæ¥çæ件å±æ§
varinfo=fs.statSync(filedir+'/'+file);
//modeæ件æé
if(info.mode===){
arr.push(filedir+'/'+file);
}
}
});
//读åæ°ç»ä¸çæ件å 容
varcontent='';
arr.forEach(function(file){
varc=fs.readFileSync(file);
content+=c.toString()+'\n';
});
//å并æ件ä¸çå 容
fs.writeFileSync('./myProject/js/index.js',content);
})
});
});
ï¼7ï¼ä½¿ç¨nodeè¿è¡webå¼å
1ãæ建ä¸ä¸ªingMessageçä¸ä¸ªå®ä¾ï¼è·å请æ±çä¸äºä¿¡æ¯ï¼å¦å¤´ä¿¡æ¯ï¼æ°æ®ç
htt
nodejs .0.0源码分析之setTimeout
本文深入剖析了Node.js .0.0版中定时器模块的实现机制。在.0.0版本中,Node.js 对定时器模块进行了重构,改进了其内部结构以提高性能和效率。下面将详细介绍定时器模块的滑稽 网站 源码关键组成部分及其实现细节。 首先,让我们了解一下定时器模块的组织结构。Node.js 采用了链表和优先队列(二叉堆)的组合来管理定时器。链表用于存储具有相同超时时间的定时器,而优先队列则用来高效地管理这些链表。 链表通过 TimersList数据结构进行管理,它允许将具有相同超时时间的定时器归类到同一队列中。这样,Node.js 能够快速定位并处理即将到期的定时器。 为了进一步优化性能,Node.js 使用了一个优先队列(二叉堆)来管理所有链表。在这个队列中,每个链表对应一个节点,根节点表示最快到期的定时器。在时间循环(timer阶段)时,Node.js 会从二叉堆中查找超时的节点,并执行相应的回调函数。 为了实现这一功能,Node.js 还维护了一个超时时间到链表的映射,以确保快速访问和管理定时器。 接下来,我们将从 setTimeout函数的实现开始分析。这个函数主要涉及 new Timeout和 insert两个操作。其中,new Timeout用于创建一个对象来存储定时器的上下文信息,而 insert函数则用于将定时器插入到优先队列中。 具体地,Node.js 使用了 scheduleTimer函数来封装底层计时操作。这个函数通过将定时器插入到libuv的二叉堆中,为每个定时器指定一个超时时间(即最快的到期时间)。在执行时间循环时,libuv会根据这个时间判断是否需要触发定时器。 当定时器触发时,Node.js 会调用 RunTimers函数来执行回调。回调函数是在Node.js初始化时设置的,负责处理定时器触发时的具体逻辑。在回调函数中,Node.js 遍历优先队列以检查是否有其他未到期的定时器,并相应地更新libuv定时器的时间。 最后,Node.js 在初始化时通过设置 processTimers函数作为超时回调来确保定时器的正确执行。通过这种方式,Node.js 保证了定时器模块的初始化和定时器触发时的执行逻辑。 本文通过详尽的分析,展示了Node.js .0.0版中定时器模块的内部机制,包括其组织结构、数据管理和回调处理等关键方面。虽然本文未涵盖所有细节,但对于理解Node.js定时器模块的实现原理提供了深入的洞察。对于进一步探索Node.js定时器模块的实现,特别是与libuv库的交互,后续文章将提供更详细的分析。nodejs之setImmediate源码分析
在lib/timer.js文件中,setImmediate函数创建了一个回调队列,等待调用者提供的回调函数执行。这个队列的处理由setImmediateCallback函数负责,该函数在timer_wrapper.cc文件中定义,接受processImmediate作为参数。在setImmediateCallback函数内部,回调信息被保存在环境env中。
具体实现中,set_immediate_callback_function宏定义了在env中保存回调函数的函数。此函数在env.cc的CheckImmediate中执行,而CheckImmediate的执行时机是在Environment::Start阶段,由uv_check_start函数在libuv库中负责。
uv_check_start函数将一个handle添加到loop的队列中,然后在uv_run循环中执行注册的CheckImmediate函数。此函数最终会调用nodejs的processImmediate函数,实现setImmediate的回调执行。
需要注意的是,setImmediate与setTimeout的执行顺序并不确定。在uv_run中,定时器的代码比uvrun_check早执行,但在执行完定时器后,若在uv__run_check之前新增定时器和执行setImmediate,setImmediate的回调会优先执行。
2024-11-13 10:49
2024-11-13 10:02
2024-11-13 09:07
2024-11-13 08:53
2024-11-13 08:52