webpack-dev-server中使用express来启动服务,我们在开发中可以在devServer中配置,在其他中间件执行前配置自己的中间件;webpack与webpack-dev-server在node环境中运行,可以通过new的方式来获得对应的实例
- React 16可以处理数组、字符串和数值 在React 15中,,一个组件的render方法必须返回单一的React元素。在React 16, 客户端渲染和服务端渲染允许组件的render 方法返回字符串,数值或者是一个元素数组。
并发模型
JS中所谓的异步并发模型和许多后台语言是不一样的,其他后天语言采用多线程来实现并发。
虽然JS是在单线程中去执行所有的操作,但它会基于事件循环的过程去实现所谓的 异步 ,从而给我们造成多线程的感觉。
栈
我们日常函数的执行,实质上基于栈去操作。JS中会存在一个调用栈,它会负责跟踪所有待执行的操作。
堆
对象被分配在堆中,堆是一个用来表示一
大块内存区域的计算机术语
console.log("start");
setImmediate(() => {
console.log("setImmediate回调发生在check阶段");
});
setTimeout(() => {
console.log("setTimeout回调发生在timers阶段");
});
process.nextTick(() => {
console.log("nextTick回调发生在同步任务执行完毕后, 微任务执行之前");
});
new Promise((res) => {
console.log("excutor");
res();
}).then(() => {
console.log("promise");
});
console.log("end");
tip:浏览器事件循环机制:我们可以知道在每次页面渲染之前是会清空所有的微任务,这也就意味着,我们对于dom的操作如果放在微任务之中是会让UI线程少绘制一次,更快的将UI展示在用户视野中。
tip: Process.nextTick会在同步任务执行完毕后,将微任务推入栈中时,会先将Process.nextTick推入栈中进行执行,
所谓process.nextTick虽然是异步API的一部分,但从技术上讲它并不是事件循环的一部分,但是我们可以完全将它理解为微任务,这两者在执行过程中是完全等价的,我们可以简单将
process.nextTick理解成为拥有最高优先级的微任务
nodejs的事件循环机制,对于我们比较重要的就是
timerspollcheck阶段
setTimeout 和 setImmediate 哪个快呢?
setTimeout和setImmediate哪个快呢? 有的时候setImmediate会先执行。之所以会造成这样的结果,是因为
setTimeout在捣鬼。在Nodejs 中
setTimeout(cb, 0)实际上存在最小执行事件1 ms, 它会被当作setTimeout(cb, 1)来执行。
- tip: 在浏览其中,
setTimeout的最小间隔是 4ms。存在这么一种场景,同步代码执行完毕,以及进入
event loop这一切发生在 1ms 之内,显然timers阶段由于代码中的setTimeout并没有达到对应的时间,换句话说它对应的callback并没有被推入当前的timer中那么,名为
timer的函数并不会被执行,会依次进入接下来的阶段,loop会一次向下进行检查。当执行到
poll阶段时,即使定时器对应的timer函数以及被推入timers中了,由于poll阶段检查到存在setImmediate所以会继续进入check阶段,并不会掉头重新进入timers中。所有在主调用栈中调用着两个API会根据
timeout以及代码执行时间,造成先输出setimmediate,之后再输出setTimeout
如何保证setImmediate 比 setTimeout快呢
我们可以再一个
I/O事件回调中,执行这两个回调,再IO回调中存在setImmediate,那么事件循环的下一个阶段一定会进入check阶段,进而一定会优先执行setImmediate回调
无论是setImmediate还是setTimeout先执行,都会伴随着本次队列中产生的微任务一同执行完毕才会进入下一个宏任务
其实它的本质和浏览器中是类似的,虽然NodeJS下存在多个执行队列,但是每次执行逻辑都是相同的:同样是执行一个宏任务后会立即清空当前队列中产生的所有微任务
串联流程
open
在主调用栈结束后,会优先处理process.nextTick以及之前产生的所有微任务
timers
之后会正式进入EventLoop事件队列,首当其中的肯定是timers定时器 callback处理阶段
每当进入timers阶段时,会检查timers中是否存在满足条件的定时器任务,当存在时,会依次取出对应的timer(定时器产生的回调)推入stack (js 执行栈)中进行执行。
每当执行完毕同时仍然会进行process.nextTick -> 微任务的步骤从而清空下一个timer任务。
poll
此后,在清空队列中所有的timers后,Loop进入poll阶段进行轮询,此阶段首先会检查是否存在对应IO的callback。
如果存在IO产生的callback, 那么推入对应JS调用栈进行执行,同样每次任务执行完毕会伴随清空随之产生的process.nextTick以及微任务
当然,如果此阶段即使产生了
timer也不会在本次Loop中执行,因为此时event loop已经达到poll阶段了。
它会依次去拿出相关的IO回调,推入stack中进行清空;
需要额外注意的时poll轮询阶段
-
如果轮询队列 不是空的,事件循环将循环访问回调队列并同步执行它们,直到队列已用尽,或者达到了与系统相关的硬性限制。
-
如果轮询队列 是空的 ,还有两件事会发生:
- 如果脚本被
setImmediate()调度,则事件循环将结束poll阶段,并继续check阶段以执行那些被调度的脚本。 - 如果脚本未被
setImmediate()调度,则事件循环将等待回调被添加到队列,然后立即执行。
- 如果脚本被