函数只有在内部工作全部执行完成后才会返回给调用者所以阻塞I/O是,应用程序通过API调用I/O操作后,当前进(线)程将会进入等待状态,代码无法继续往下执行,这时CPU可以进行进(线)程调度,即切换到其他可执行的进...(线)程继续执行,当前进(线)程在底层I/O请求处理完后才会返回并可以继续执行多进(线)程 + 阻塞I/O模型有什么问题?...我们可以以异步的方式去进行I/O操作,通过API调用I/O操作后会马上返回,紧接着就可以继续执行其他代码逻辑,那为什么nodejs中的I/O是“非阻塞”的呢?...I/O请求,等待数据准备好(如网络I/O,等待数据从网络中到达socket;等待系统从磁盘上读取数据等)数据准备好后,复制到内核缓冲区从内核空间复制到用户空间,用户程序拿到数据接下来我们看一下操作系统中有哪些...content = Read('text.txt'); // 发出事件调用nodejs提供的callback});通过I/O多路复用 + 多线程模拟的异步I/O配合事件循环机制,nodejs
函数只有在内部工作全部执行完成后才会返回给调用者所以阻塞I/O是,应用程序通过API调用I/O操作后,当前进(线)程将会进入等待状态,代码无法继续往下执行,这时CPU可以进行进(线)程调度,即切换到其他可执行的进...(线)程继续执行,当前进(线)程在底层I/O请求处理完后才会返回并可以继续执行多进(线)程 + 阻塞I/O模型有什么问题?...我们可以以异步的方式去进行I/O操作,通过API调用I/O操作后会马上返回,紧接着就可以继续执行其他代码逻辑,那为什么nodejs中的I/O是“非阻塞”的呢?...(如网络I/O,等待数据从网络中到达socket;等待系统从磁盘上读取数据等)数据准备好后,复制到内核缓冲区从内核空间复制到用户空间,用户程序拿到数据接下来我们看一下操作系统中有哪些I/O模型参考nodejs...content = Read('text.txt'); // 发出事件调用nodejs提供的callback});通过I/O多路复用 + 多线程模拟的异步I/O配合事件循环机制,nodejs
当js执行碰到事件绑定和一些异步操作(如setTimeOut,也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会走事件触发线程将对应的事件添加到对应的线程中(比如定时器操作,便把定时器事件添加到定时器线程...简单说就是当执行到一个http异步请求时,就把异步请求事件添加到异步请求线程,等收到响应(准确来说应该是http状态变化),再把回调函数添加到事件队列,等待js引擎线程来执行宏任务与微任务了解JavaScript...第一轮loop,继续执行主代码块,进行new Promise,执行Promise的executor,输出步骤7,并修改Promise为完成态。...通常,在执行代码时,事件循环最终会命中轮询阶段,在那等待传入连接、请求等。...使用process.nextTick的两个重要原因:允许用户处理错误,清理任何不需要的资源,或者在事件循环继续之前重试请求。有时有让回调在栈展开后,但在事件循环继续之前运行的必要。
虽然单线程简化了编程代码,因为这样咱们不必太担心并发引出的问题,这也意味着在阻塞主线程的情况下执行长时间的操作,如网络请求。...使用异步 (如 回调函数、promise、async/await),可以不用阻塞主线程的情况下长时间执行网络请求。 了解异步的工作方式之前,咱们先来看看同步是怎么样工作的。...同步 JS 是如何工作的? 在深入研究异步JS之前,先来了解同步 JS 代码在 JavaScript 引擎中执行情况。...因此,在执行上述代码时,咱们不能执行任何其他操作,这是不理想的。 解决办法是什么? 最简单的解决方案是异步回调,各位使用异步回调使代码非阻塞。...在Nodejs中,web api被c/c++ api所替代。 现在让我们回到上面的代码,看看它是如何异步执行的。
一. nodejs背景 先来说说nodejs最常被提到的几个关键词,“单线程”,“非阻塞异步IO”,“事件循环”。接下来主要来通过这几个关键字总结一下nodejs的内在原理,以及引申出的一些问题。...三. nodejs的异步IO 再拿上面的例子来看,当100个用户请求同时被接受到时,当需要IO(网络IO/文件IO)操作时,单线程的javascript并不会停下来等待IO操作完成,而是“事件驱动”开始介入...,javascript执行线程继续执行未完的javascript代码,当执行完成后该线程处于空闲状态,可以看下面这一段代码示例。...可以看出100个请求均是在请求返回之前非常短的时间都被得到了处理,而返回则均在请求之后,并非请求按接收顺序依次等待各个IO得到处理后依次返回。 四....可以思考一下,读操作是线程池来控制执行的,在该线程执行前,先在注册事件的内存中初始化一个状态是“执行中”,并且事件循环也已经被激活,开始轮询等待执行结果,当执行IO的线程在执行完之后,再通过底层的异步IO
例如,当微任务队列完成时,或者说计时器操作执行了 Promise 操作,事件循环将会在继续进入计时器队列中的其他函数之前参与该 Promise 操作。 因此,微任务队列比其他队列具有最高的优先级。...因为 readFile 操作是异步的,所以会移交给 Node.js,之后程序将会继续执行。 do while 操作持续 3ms。在这段时间内,readFile 操作完成并被推送到 IO 队列。...# 返回 "last line" "setTimeout" 当事件循环继续执行队列中的回调函数时,promise 操作完成并被添加到微任务队列中: // 队列 Timer = [];...并不取决于它们在程序中的存放顺序。 事件循环在每次迭代之继续检查其他任务之前,会连续检查微任务队列。 即使在后台有另一个 IO 操作(readFile),事件循环也会执行检查队列中的函数。...事件循环会确定将要在每次迭代中接下来要执行的回调函数。 了解队列如何在 Node.js 中工作,使你对其有了更好的了解,因为队列是环境的核心功能之一。
nodejs中阻塞和非阻塞IO nodejs 对于大部分的 I/O 操作都提供了阻塞和非阻塞两种用法。阻塞指的是执行 I/O 操作的时候必须等待结果,才往下执行 js 代码。...请求对象与线程池 从 JavaScript 调用到计算机系统执行完 I/O 回调,请求对象充当着很重要的作用,我们还是以一次异步 I/O 操作为例 请求对象: 比如之前调用 fs.readFile ,本质上调用...然后异步调用的第一阶段就完成了,JavaScript 会继续往下执行执行栈上的代码逻辑,当前的 I/O 操作将以请求对象的形式放入到线程池中,等待执行。达到了异步 I/O 的目的。...第三阶段:事件循环中 I/O 观察者,会从请求对象中找到已经得到结果的 I/O 请求对象,取出结果和回调函数,将回调函数放入事件循环中,执行回调,完成整个异步 I/O 任务。...当 timeout = -1时,说明会一直阻塞事件循环,那么此时就可以停留在异步 I/O 的 poll 阶段,等待新的 I/O 任务完成。
在上一篇文章在chromev8中的JavaScript事件循环分析中分析到,在chrome中的js引擎是通过执行栈和事件队列的形式来完成js的异步操作。...JavaScript中几乎所有的I/O基元都是非阻塞的,如网络请求、文件系统操作等。...check 正常来说,在执行代码时,事件循环最终将进入poll阶段,在该阶段,它将等待传入连接、请求等。...通过使用process.nextTick(),我们保证apiCall()始终在用户代码的其余部分之后和允许事件循环继续之前运行其回调。...callbacks完成一个执行周期,其中的poll用来处理异步操作 参考资料 https://zhuanlan.zhihu.com/p/33058983 http://nodejs.cn/learn/
setTimeout/clearTimeout - 用于在指定的毫秒数后执行代码块(仅执行一次) setInterval/clearInterval - 用于在指定的毫秒数后循环执行代码块(循环执行)...setImmediate/clearImmediate - 在当前事件循环周期结束后执行代码块 process.nextTick - 在当前执行栈尾部,Event-Loop 之前触发 timer 的执行顺序...总结起来一句话概括,事件轮询是 JS 实现异步的具体解决方案,同步代码直接执行,异步函数或代码块先放在异步队列中,待同步函数执行完毕,轮询执行异步队列的函数。...众所周知,JavaScript 是单线程的,当发起一个请求时会通过回调函数来接收后续的事件响应,不会造成阻塞,继续接收下一次请求操作。 ?...如果此时事件队列中有消息,则会等待其它的消息完成之后,在去处理我们的 msg 事件消息并将完成结果渲染到 DOM 中。 Q5: 解释下 NodeJS 中的 EventLoop(事件循环)?
所以必须要让js线程在网络调用时停下来,等待消息返回后,再继续执行。...before,在realAsyncFunction的then函数执行,cb被调用之前,js线程就会卡死在原地,不执行后面的代码,直到异步过程返回后,继续打印after。...Event Loop:事件循环。 如何理解最后两项呢? 用户代码在主线程执行,如果执行过程中,遇到一个异步调用,js引擎就会封装一个请求对象,并且注册到线程池去。...在操作系统进行上述过程的时候,我们的用户代码还在V8引擎里继续执行着,直到执行到末尾,主线程结束,进入事件循环阶段。...但我们通过调用deasync.runLoopOnce(),在主线程代码执行完成前,强行激活了事件循环,事件循环会检查观察者,如果这时异步调用返回了结果,它的回调函数也会被执行。
的架构在继续讨论nodejs event loop之前,我们不妨来看看nodejs的架构图:图片从上面的架构图,你可以看出,libuv是位于架构的最底层的。...或许我们可以这样说,所有的同步代码的执行都是由v8来完成的,所有异步代码的执行都是由libuv提供的event loop功能模块来完成的。那event loop与v8是什么关系呢?...入口文件被看作是同步代码,由v8来执行。在从上到下的解释/编译的过程中,如果遇到执行异步代码的请求的时候,nodejs就会把它交给event loop来执行。...之所以说它是“半无限”,是因为当没有任何任务(更多的异步I/O请求或者timer)要做的的时候,event loop会退出这个循环,整个nodejs程序也就执行完成了。...只有等待时间超出了nodejs计算出来的限定时间或者再也没有未完成的I/O任务的时候,nodejs才会退出event loop。
JavaScript是解析性语言,代码按照编码顺序一行一行被压进stack里面执行,执行完成后移除然后继续压下一行代码块进去执行。...上面代码块的堆栈图,当主线程接受了request后,程序被压进同步执行的sleep执行块(我们假设这里就是程序的业务处理),如果在这10s内有第二个request进来就会被压进stack里面等待10s执行完成后再进一步处理下一个请求...,后面的请求都会被挂起等待前面的同步执行完成后再执行。...当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。 ...2、nodejs所谓的单线程,只是主线程是单线程,所有的网络请求或者异步任务都交给了内部的线程池去实现,本身只负责不断的往返调度,由事件循环不断驱动事件执行。
一种是setTimeout定时器作为代表的,触发后直接进入事件队列等待执行;一种是XMLHTTPRequest代表的,触发后需要调用去另一个线程执行,执行完成后封装返回值进入事件队列等待。...直至实现了微任务,才可以认为JavaScript的代码执行存在了异步过程。...其实这个问题在之前的业务开发中遇到过。由于微任务执行的时序与定义不符,导致数据出现了微小的差异。这里与Nodejs版本迭代中的实现有关。...而通过查看Nodejs版本日志发现,在Nodejs环境中,在11版本之前,同源的任务放在一起进行执行,也就是宏任务队列和微任务队列只有清空一个后才会执行另一个。...就算涉及到同源宏任务的嵌套代码,任然会将宏任务一起执行,但是内部的任务则会放到下一个循环中去执行。而在11版本后,Nodejs修改成了与浏览器一样的遵循定义的执行方式。
JavaScript是解析性语言,代码按照编码顺序一行一行被压进stack里面执行,执行完成后移除然后继续压下一行代码块进去执行。...上面代码块的堆栈图,当主线程接受了request后,程序被压进同步执行的sleep执行块(我们假设这里就是程序的业务处理),如果在这10s内有第二个request进来就会被压进stack里面等待10s执行完成后再进一步处理下一个请求...,后面的请求都会被挂起等待前面的同步执行完成后再执行。...当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。...2、nodejs所谓的单线程,只是主线程是单线程,所有的网络请求或者异步任务都交给了内部的线程池去实现,本身只负责不断的往返调度,由事件循环不断驱动事件执行。
JavaScript是解析性语言,代码按照编码顺序一行一行被压进stack里面执行,执行完成后移除然后继续压下一行代码块进去执行。...上面代码块的堆栈图,当主线程接受了request后,程序被压进同步执行的sleep执行块(我们假设这里就是程序的业务处理),如果在这10s内有第二个request进来就会被压进stack里面等待10s执行完成后再进一步处理下一个请求...,后面的请求都会被挂起等待前面的同步执行完成后再执行。...当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。...3、主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行
2.JS引擎线程:JS内核,负责处理Javascript脚本,解析和运行JS代码(如V8引擎),一个TAB页中仅有一个JS线程在运行JS程序。...注意:GUI线程和JS引擎线程是互斥的,当JS引擎线程执行的时候,GUI线程会被挂起,阻塞页面渲染。待JS引擎空闲的时候才会继续执行。 3.事件触发线程:归属于浏览器而不是JS引擎,用来控制事件循环。...当执行setTimeout/鼠标点击/Ajax请求等事件时,会将对应异步任务添加到事件线程中。当事件符合触发条件时,该线程会将其添加到事件队列的队尾,等待JS引擎线程处理。...定时器线程 js中跑的setTimeout、setInterval等定时器,是一个单独的线程管理的控制的,当计时完成就会将特定的事件推送到事件队列中。等待主线程执行。...(如:promise、process.nextTick等,mutationobserver 可用来实现微任务) process.nextTick() 的回调将在事件循环继续之前解析,所以微任务里面,process.nextTick
这样就把等待的时间充分利用了起来,提高了执行效率,但是同时又会产生一个问题,nodejs 应用程序怎么知道操作系统已经完成了 I/O 操作呢?...好,至此现在js的调用就直接返回了,我们的 js 应用程序代码可以继续往下执行,当然,当前的 I/O 操作同时也在线程池中将被执行,这不就完成了异步么:) 等等,别高兴太早,回调都还没执行呢!...还记得之前讲过的 eventLoop 吗?在每一个Tick当中会调用GetQueuedCompletionStatus检查线程池中是否有执行完的请求,如果有则表示时机已经成熟,可以执行回调了。...一旦 EventLoop 的轮询操作中,调用GetQueuedCompletionStatus检测到了完成的状态,就会把请求对象塞给I/O观察者(之前埋下伏笔,如今终于闪亮登场)。...nodejs中的异步 I/O 采用多线程的方式,由 EventLoop、I/O 观察者,请求对象、线程池四大要素相互配合,共同实现。
线程池 线程池,是一种线程的使用模式,它为了降低线程使用中频繁的创建和销毁所带来的资源消耗与代价。通过创建一定数量的线程,让他们时刻准备就绪等待新任务的到达,而任务执行结束之后再重新回来继续待命。...从前面到达 libuv ,会有一个参数,请求对象,也就是open函数前面整个流程传递进来的请求对象,它保存了所有状态,包括送入线程池等待执行以及I/O操作完毕后的回调处理。...在这整个过程中,进程初期创建的事件循环中有一个 I/O 观察者,每次 Tick 的执行中,它会调用 IOCP 相关的方法检查线程池中是否有执行完成的请求,如果存在,会讲请求对象和之前绑定的 result...★重要:虽然 libuv 的异步文件 I/O 操作是通过线程池实现的,但是网络 I/O 总是在单线程中执行的,注意最后还是会把完成的内容作为事件加入事件循环,事件循环就和文件I/O相同了。...” 异步 I/O 助力 Node.js 高性能 传统的服务器模型 同步式: 同步的服务,一次只能处理一个请求,并且其余请求都处于等待状态。
运行完成后,浏览器可以继续其他调度,重新渲染页面的UI或者去执行垃圾回收 一些异步任务的回调会以此进入 macrotask queue(宏任务队列),等等后续被调用,这些异步函数包括: setTimeout...微任务是更小的任务,微任务更新应用程序的状态,但是必须在浏览器任务继续执行其他任务之前执行,浏览器任务包括重新渲染页面的UI。...微任务能使得我们能够在重新渲染UI之前执行指定的行为,避免不必要的UI重绘,UI重绘会使得应用状态不连续 另一些异步回调会进入 microtask queue(微任务队列) ,等待后续被调用,这些异步函数包括...当前轮的微任务优先于宏任务异步操作先执行,执行完成到 loop 中,进入到下一轮。下一轮执行之前的宏任务的异步操作,比如 setTimeout 。...此时,如果这个异步任务中还有微任务,那么就会执行完成这个微任务,在执行下一个异步任务。就这样一次的循环。
领取专属 10元无门槛券
手把手带您无忧上云