//27、review
//1
/*
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="button">按钮</div>
<script type="text/javascript">
button.addEventListener('click',()=>{
console.log('listener1');
Promise.resolve().then(()=>console.log('micro task1'));
})
button.addEventListener('click',()=>{
console.log('listener2');
Promise.resolve().then(()=>console.log('micro task2'));
})
button.click();
//不点击时执行
//listener1
//listener2
// micro task1
// micro task2
//点击按钮执行(点击button执行,点击之前,这些事件都放在宏任务队列中)
//listener1
//micro task1
//listener2
//micro task2
</script>
</body>
</html>
*/
/*
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
Promise.resolve().then(()=>{
console.log('Promise1');
setTimeout(()=>{
console.log('setTimeout2');
},0);
})
setTimeout(()=>{
console.log('setTimeout1');
Promise.resolve().then(()=>{
console.log('Promise2');
})
},0);
//Promise1
//setTimeout1
//Promise2
//setTimeout2
//宏任务[setTimeout1] => [setTimeout1,setTimeout2] => [setTimeout2]
//微任务[Promise1] [] [Promise2]
</script>
</body>
</html>
*/
/*
//async返回的是一个promise generator+co
//await =>yield 如果产出的是一个promise,会调用这个promise.then方法
//浏览器是识别async+await await后面跟的是promise的话默认就会直接调用这个promise的then方法
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end');
【等价替换await async2();console.log('async1 end');
(1)浏览器中
async2().then(()=>{
console.log('async1 end');
});
(2)node中(两次then)
new Promise((resolve,reject)=>resolve(async2())).then(()=>{console.log('async1 end');})
//在node中的执行结果script start,async1 start,async2,promise1,script end,promise2,async1 end,setTimeout
】
}
async function async2(){
console.log('async2');
}
console.log('script start');
setTimeout(function(){
console.log('setTimeout');
},0);
async1();
new Promise(function(resolve){ //一次then
console.log('promise1');
resolve();
}).then(function(){
console.log('promise2');
});
console.log('script end');
//默认执行 script start,async1 start,async2,promise1,script end
//宏任务[setTimeout]
//微任务[async1 end,promise2]
//结果script start,async1 start,async2,promise1,script end,async1 end,promise2,setTimeout
//在node中的执行结果script start,async1 start,async2,promise1,script end,async1 end,promise2,setTimeout
</script>
</body>
</html>
*/
//28、node中的基本概念
//Web主要场景就是接收客户端的请求读取静态资源和渲染页面,所以Node非常适合Web应用的开发。
//阻塞和非阻塞 针对的是调用方
//>我调用了一个方法之后的状态 fs.readFile
//同步异步 针对的是被调用方
//>我调用了一个方法,这个方法会给我说他是同步的还是异步的
//异步非阻塞(我调用了一个方法,这个方法是异步的,我不想要等待这个方法执行完毕)
//http第一个请求 要计算100万个数相加,第二个请求来了,需要等待第一个人计算完成
//29、commander的用法
//node和前端的区别:前端里面有DOM、BOM,服务器端中没有window
//服务器中有global属性 全局对象
console.log(Object.keys(global));
//process 进程(很重要)
//Buffer类型 来处理二进制文件
//clearInterval clearTimeout
//setInterval setTimeout
//clearImmediate setImmediate 宏任务
//浏览器以前的方法,还是可以使用的只是默认没有被枚举出来
//console.dir(global,{showHidden:true});
//1、process默认取值时会在global中查找(node中有一个模块化系统,是以文件为单位的,每个文件都是一个模块,模块中的this被更改了 this:{})
//console.log(Object.keys(process));
//console.log(process);
//console.log(process.platform); //可以用这个属性来判断当前执行的系统环境 win32 darwin
// console.log(process.argv);//1、node.exe 2、node当前执行的文件(解析用户自己传递的参数)
//C:\Users\dptech\Desktop\test>node test.js a b c
/*
[
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\dptech\\Desktop\\test\\test.js',
'a',
'b',
'c'
]
*/
//执行node文件 node文件名 a b c d (webpack --mode --config --port --progress)
//console.log(process.cwd());//当前用户的工作目录 current working directory
//console.log(process.env);//环境变量
//console.log(process.nextTick);
//result: >node test.js
//[Function: nextTick]
//console.log(process.argv);
let args = process.argv.slice(2);
//['--port','3000','--color','red','--config','a.js'];
let obj = {};
args.forEach((item,index)=>{
if(item.startsWith('--')){
obj[item.slice(2)] = args[index+1];
}
});
console.log(obj);
/*
>node test.js --port 3000 --color red --config a.js
{ port: '3000', color: 'red', config: 'a.js' }
*/
/*
commander TJ
yargs webpack npm github
在npm上的模块都需要先安装再使用.(模块内部也提供了几个属性,也可以在模块中直接访问--参数)
*/
/*
npm init -y
npm install commander
*/
const program = require('commander');
let r = program.parse(process.argv);
/*
C:\Users\dptech\Desktop\test>node test.js a.txt
<ref *1> Command {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
commands: [],
options: [],
parent: null,
_allowUnknownOption: false,
_args: [],
rawArgs: [
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\dptech\\Desktop\\test\\test.js',
'a.txt'
],
*/
const program = require('commander'); //--开头的是key,不带--是值
program.option('-p,--port <v>','set your port');
program.option('-c,--config <v>','set your config file');
let r = program.parse(process.argv);
console.log(r);
/*
C:\Users\dptech\Desktop\test>node test.js -p 111 -c 222
<ref *1> Command {
_events: [Object: null prototype] {
'option:port': [Function (anonymous)],
'option:config': [Function (anonymous)]
},
_eventsCount: 2,
_maxListeners: undefined,
commands: [],
options: [
Option {
flags: '-p,--port <v>',
required: true,
optional: false,
mandatory: false,
negate: false,
short: '-p',
long: '--port',
description: 'set your port',
defaultValue: undefined
},
Option {
flags: '-c,--config <v>',
required: true,
optional: false,
mandatory: false,
negate: false,
short: '-c',
long: '--config',
description: 'set your config file',
defaultValue: undefined
}
],
parent: null,
_allowUnknownOption: false,
_args: [],
rawArgs: [
'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\dptech\\Desktop\\test\\test.js',
'-p',
'111',
'-c',
'222'
],
_scriptPath: 'C:\\Users\\dptech\\Desktop\\test\\test.js',
_name: 'test',
_optionValues: {},
_storeOptionsAsProperties: true,
_passCommandToAction: true,
_actionResults: [],
_actionHandler: null,
_executableHandler: false,
_executableFile: null,
_defaultCommandName: null,
_exitCallback: null,
_aliases: [],
_hidden: false,
_helpFlags: '-h, --help',
_helpDescription: 'display help for command',
_helpShortFlag: '-h',
_helpLongFlag: '--help',
_hasImplicitHelpCommand: 0,
_helpCommandName: 'help',
_helpCommandnameAndArgs: 'help [command]',
_helpCommandDescription: 'display help for command',
program: [Circular *1],
Command: [Function: Command],
Option: [Function: Option],
CommanderError: [Function: CommanderError],
port: '111',
config: '222',
args: [],
[Symbol(kCapture)]: false
}
*/
const program = require('commander');
program.version('1.0.0').command('create').action(()=>{
console.log('创建项目');
})
.name('node')
.usage('my-server')
.option('-p,--port <v>','set your port')
.option('-c,--config <v>','set your config file')
.parse(process.argv);
console.log(process.argv);
//30、node中的eventloop
const program = require('commander');
console.log(process.cwd());//当前用户的工作目录 current working directory(这个目录可以更改,用户自己切换即可)
//当前用户在哪执行node命令时,就去哪找配置文件 webpack
console.log(__dirname);//当前文件所在的目录,这个目录是不能手动修改的
console.log(process.env);//环境变量 可以根据环境变量实现不同的功能
//window set key=value mac export key=value 这样设置的环境变量是临时的变量
/*
C:\Users\dptech\Desktop\test>node test.js
C:\Users\dptech\Desktop\test
C:\Users\dptech\Desktop\test
{
ALLUSERSPROFILE: 'C:\\ProgramData',
APPDATA: 'C:\\Users\\dptech\\AppData\\Roaming',
CLIENTNAME: 'LCCPC',
CommonProgramFiles: 'C:\\Program Files\\Common Files',
'CommonProgramFiles(x86)': 'C:\\Program Files (x86)\\Common Files',
CommonProgramW6432: 'C:\\Program Files\\Common Files',
COMPUTERNAME: 'DESKTOP-HDPMBFM',
ComSpec: 'C:\\WINDOWS\\system32\\cmd.exe',
DriverData: 'C:\\Windows\\System32\\Drivers\\DriverData',
HOMEDRIVE: 'C:',
HOMEPATH: '\\Users\\dptech',
LOCALAPPDATA: 'C:\\Users\\dptech\\AppData\\Local',
LOGONSERVER: '\\\\DESKTOP-HDPMBFM',
NUMBER_OF_PROCESSORS: '2',
OneDrive: 'C:\\Users\\dptech\\OneDrive',
OS: 'Windows_NT',
Path: 'C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\nodejs\\;D:\\Program Files\\Git\\Git\\cmd;;D:\\Program Files (x86)\\vscode\\Microsoft VS Code\\bin;C:\\Users\\dptech\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\dptech\\AppData\\Roaming\\npm',
PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
PROCESSOR_ARCHITECTURE: 'AMD64',
PROCESSOR_IDENTIFIER: 'Intel64 Family 6 Model 60 Stepping 3, GenuineIntel',
PROCESSOR_LEVEL: '6',
PROCESSOR_REVISION: '3c03',
ProgramData: 'C:\\ProgramData',
ProgramFiles: 'C:\\Program Files',
'ProgramFiles(x86)': 'C:\\Program Files (x86)',
ProgramW6432: 'C:\\Program Files',
PROMPT: '$P$G',
PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules',
PUBLIC: 'C:\\Users\\Public',
SESSIONNAME: 'RDP-Tcp#1',
SystemDrive: 'C:',
SystemRoot: 'C:\\WINDOWS',
TEMP: 'C:\\Users\\dptech\\AppData\\Local\\Temp',
TMP: 'C:\\Users\\dptech\\AppData\\Local\\Temp',
USERDOMAIN: 'DESKTOP-HDPMBFM',
USERDOMAIN_ROAMINGPROFILE: 'DESKTOP-HDPMBFM',
USERNAME: 'dptech',
USERPROFILE: 'C:\\Users\\dptech',
windir: 'C:\\WINDOWS'
}
*/
let domain = process.env.NODE_ENV == 'production'?'localhost':'zfpx.com';
console.log(process.nextTick);
//(1)微任务(node中自己实现的微任务)nextTick queueMicrotask
//node中还增加了一个
queueMicrotask(()=>{
console.log(1);
})
setTimeout(()=>{
console.log(2);
},0);
//执行结果1 2
//(2)node中setImmediate宏任务
//常见面试题:node中的事件环和浏览器中的区别
//微任务有哪些,宏任务有哪些
//事件环
//timer
//pending callbacks
//idle,prepare
//poll
//check
//close callbacks
//浏览器的事件环和node事件环 执行效果现在是一致的了
//进入事件环时,setTimeout有可能没有完成
setTimeout(()=>{
console.log('timeout');
},0);
setImmediate(()=>{
console.log('setImmeditate');
});
//结果有时是timeout->setImmediate 有时是setImmediate->timeout
//poll完成后,setImmediate->setTimeout
let fs = require('fs');
fs.readFile('./name.txt',()=>{
setTimeout(()=>{
console.log('timeout');
},0);
setImmediate(()=>{
console.log('setImmediate');
});
})
//process.nextTick并不属于事件环的一部分,在本轮代码执行后执行
setTimeout(()=>{
console.log(1);
Promise.resolve().then(()=>{
console.log('then');
})
process.nextTick(()=>{
console.log('nextTick');
})
},0);
setTimeout(()=>{
console.log(2);
},0);
/*
>node test.js
1
nextTick
then
2
*/
/*
(网上找的答案)
浏览器中的Event loop
浏览器的任务队列分为宏任务和微任务
宏任务:setTimeout, setInterval, setImmediate, I/O,原生事件回调函数,MessageChannel、postMessage等。
微任务:process.nextTick, 原生Promise(有些实现的promise将then方法放到了宏任务中),Object.observe(已废弃), MutationObserver等。
那么浏览器中的任务执行顺序是怎么样的呢?
1、浏览器中,先执行当前栈,执行完主执行线程中的任务。
2、取出Microtask微任务队列中任务执行直到清空。
3、取出Macrotask宏任务中 一个 任务执行。
4、检查Microtask微任务中有没有任务,如果有任务执行直到清空。
5、重复3和4。
整个的这种运行机制又称为Event Loop(事件循环)
node中的Event loop
1、在libuv内部有这样一个事件环机制。在node启动时会初始化事件环。
2、node中的event loop分为6个阶段,不同于浏览器的是,这里每一个阶段都对应一个事件队列,node会在当前阶段中的全部任务执行完,清空NextTick Queue,清空Microtask Queue,再执行下一阶段。
3、在node.js里,process 对象代表node.js应用程序,可以获取应用程序的用户,运行环境等各种信息。process.nextTick()方法将 callback 添加到next tick 队列,并且nextTick优先级比promise等microtask高。
timers:执行setTimeout() 和 setInterval()中到期的callback。
I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的
这一阶段执行 idle, prepare:队列的移动,仅内部使用
poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段
check:执行setImmediate的callback
close callbacks:执行close事件的callback,例如socket.on("close",func)
*/