Node.js事件循环

上传人:一*** 文档编号:145573630 上传时间:2020-09-21 格式:DOCX 页数:32 大小:131.12KB
返回 下载 相关 举报
Node.js事件循环_第1页
第1页 / 共32页
Node.js事件循环_第2页
第2页 / 共32页
Node.js事件循环_第3页
第3页 / 共32页
Node.js事件循环_第4页
第4页 / 共32页
Node.js事件循环_第5页
第5页 / 共32页
点击查看更多>>
资源描述

《Node.js事件循环》由会员分享,可在线阅读,更多相关《Node.js事件循环(32页珍藏版)》请在金锄头文库上搜索。

1、Node.js 事件循环目录 介绍 阻塞事件循环 调用堆栈 一个简单的事件循环的阐释 入队函数执行 消息队列 ES6 作业队列介绍事件循环是了解 Node.js 最重要的方面之一。为什么这么重要? 因为它阐明了 Node.js 如何做到异步且具有非阻塞的 I/O,所以它基本上阐明了 Node.js 的“杀手级应用”,正是这一点使它成功了。Node.js JavaScript 代码运行在单个线程上。 每次只处理一件事。这个限制实际上非常有用,因为它大大简化了编程方式,而不必担心并发问题。只需要注意如何编写代码,并避免任何可能阻塞线程的事情,例如同步的网络调用或无限的循环。通常,在大多数浏览器中,

2、每个浏览器选项卡都有一个事件循环,以使每个进程都隔离开,并避免使用无限的循环或繁重的处理来阻止整个浏览器的网页。该环境管理多个并发的事件循环,例如处理 API 调用。 Web 工作进程也运行在自己的事件循环中。主要需要关心代码会在单个事件循环上运行,并且在编写代码时牢记这一点,以避免阻塞它。阻塞事件循环任何花费太长时间才能将控制权返回给事件循环的 JavaScript 代码,都会阻塞页面中任何 JavaScript 代码的执行,甚至阻塞 UI 线程,并且用户无法单击浏览、滚动页面等。JavaScript 中几乎所有的 I/O 基元都是非阻塞的。 网络请求、文件系统操作等。 被阻塞是个异常,这就

3、是 JavaScript 如此之多基于回调(最近越来越多基于 promise 和 async/await)的原因。调用堆栈调用堆栈是一个 LIFO 队列(后进先出)。事件循环不断地检查调用堆栈,以查看是否需要运行任何函数。当执行时,它会将找到的所有函数调用添加到调用堆栈中,并按顺序执行每个函数。你知道在调试器或浏览器控制台中可能熟悉的错误堆栈跟踪吗? 浏览器在调用堆栈中查找函数名称,以告知你是哪个函数发起了当前的调用:一个简单的事件循环的阐释举个例子:const bar = () = console.log(bar)const baz = () = console.log(baz)const

4、foo = () = console.log(foo) bar() baz()foo()此代码会如预期地打印:foobarbaz当运行此代码时,会首先调用foo()。 在foo()内部,会首先调用bar(),然后调用baz()。此时,调用堆栈如下所示:每次迭代中的事件循环都会查看调用堆栈中是否有东西并执行它直到调用堆栈为空:入队函数执行上面的示例看起来很正常,没有什么特别的:JavaScript 查找要执行的东西,并按顺序运行它们。让我们看看如何将函数推迟直到堆栈被清空。setTimeout() = , 0)的用例是调用一个函数,但是是在代码中的每个其他函数已被执行之后。举个例子:const

5、bar = () = console.log(bar)const baz = () = console.log(baz)const foo = () = console.log(foo) setTimeout(bar, 0) baz()foo()该代码会打印:foobazbar当运行此代码时,会首先调用 foo()。 在 foo() 内部,会首先调用 setTimeout,将bar作为参数传入,并传入 0 作为定时器指示它尽快运行。 然后调用 baz()。此时,调用堆栈如下所示:这是程序中所有函数的执行顺序:为什么会这样呢?消息队列当调用 setTimeout() 时,浏览器或 Node.js

6、 会启动定时器。 当定时器到期时(在此示例中会立即到期,因为将超时值设为 0),则回调函数会被放入“消息队列”中。在消息队列中,用户触发的事件(如单击或键盘事件、或获取响应)也会在此排队,然后代码才有机会对其作出反应。 类似onLoad这样的 DOM 事件也如此。事件循环会赋予调用堆栈优先级,它首先处理在调用堆栈中找到的所有东西,一旦其中没有任何东西,便开始处理消息队列中的东西。我们不必等待诸如setTimeout、fetch、或其他的函数来完成它们自身的工作,因为它们是由浏览器提供的,并且位于它们自身的线程中。 例如,如果将setTimeout的超时设置为 2 秒,但不必等待 2 秒,等待发

7、生在其他地方。ES6 作业队列ECMAScript 2015 引入了作业队列的概念,Promise 使用了该队列(也在 ES6/ES2015 中引入)。 这种方式会尽快地执行异步函数的结果,而不是放在调用堆栈的末尾。在当前函数结束之前 resolve 的 Promise 会在当前函数之后被立即执行。有个游乐园中过山车的比喻很好:消息队列将你排在队列的后面(在所有其他人的后面),你不得不等待你的回合,而工作队列则是快速通道票,这样你就可以在完成上一次乘车后立即乘坐另一趟车。示例:const bar = () = console.log(bar)const baz = () = console.l

8、og(baz)const foo = () = console.log(foo) setTimeout(bar, 0) new Promise(resolve, reject) = resolve(应该在 baz 之后、bar 之前) ).then(resolve = console.log(resolve) baz()foo()这会打印:foobaz应该在 baz 之后、bar 之前bar这是 Promise(以及基于 promise 构建的 async/await)与通过setTimeout()或其他平台 API 的普通的旧异步函数之间的巨大区别。了解 process.nextTick()

9、当尝试了解 Node.js 事件循环时,其中一个重要的部分就是process.nextTick()。每当事件循环进行一次完整的行程时,我们都将其称为一个滴答。当将一个函数传给process.nextTick()时,则指示引擎在当前操作结束(在下一个事件循环滴答开始之前)时调用此函数:process.nextTick() = /做些事情)事件循环正在忙于处理当前的函数代码。当该操作结束时,JS 引擎会运行在该操作期间传给nextTick调用的所有函数。这是可以告诉 JS 引擎异步地(在当前函数之后)处理函数的方式,但是尽快执行而不是将其排入队列。调用setTimeout() = , 0)会在下一

10、个滴答结束时执行该函数,比使用nextTick()(其会优先执行该调用并在下一个滴答开始之前执行该函数)晚得多。当要确保在下一个事件循环迭代中代码已被执行,则使用nextTick()。了解 setImmediate()当要异步地(但要尽可能快)执行某些代码时,其中一个选择是使用 Node.js 提供的setImmediate()函数:setImmediate() = /运行一些东西)作为 setImmediate() 参数传入的任何函数都是在事件循环的下一个迭代中执行的回调。setImmediate()与setTimeout() = , 0)(传入 0 毫秒的超时)、process.nextT

11、ick()有何不同?传给process.nextTick()的函数会在事件循环的当前迭代中(当前操作结束之后)被执行。 这意味着它会始终在setTimeout和setImmediate之前执行。延迟 0 毫秒的setTimeout()回调与setImmediate()非常相似。 执行顺序取决于各种因素,但是它们都会在事件循环的下一个迭代中运行。探索 JavaScript 定时器目录 setTimeout()o 零延迟 setInterval() 递归的 setTimeoutsetTimeout()当编写 JavaScript 代码时,可能希望延迟函数的执行。这就是 setTimeout 的工作

12、。 指定一个回调函数以供稍后执行,并指定希望它稍后运行的时间(以毫秒为单位)的值:setTimeout() = / 2 秒之后运行, 2000)setTimeout() = / 50 毫秒之后运行, 50)该语法定义了一个新的函数。 可以在其中调用所需的任何其他函数,也可以传入现有的函数名称和一组参数:const myFunction = (firstParam, secondParam) = / 做些事情/ 2 秒之后运行setTimeout(myFunction, 2000, firstParam, secondParam)setTimeout会返回定时器的 id。 通常不使用它,但是可以

13、保存此 id,并在要删除此安排的函数执行时清除它:const id = setTimeout() = / 应该在 2 秒之后运行, 2000)/ 改变主意了clearTimeout(id)零延迟如果将超时延迟指定为0,则回调函数会被尽快执行(但是是在当前函数执行之后):setTimeout() = console.log(后者 ), 0)console.log( 前者 )会打印前者 后者。通过在调度程序中排队函数,可以避免在执行繁重的任务时阻塞 CPU,并在执行繁重的计算时执行其他函数。某些浏览器(IE 和 Edge)实现的setImmediate()方法具有相同的确切功能,但是不是标准的,并

14、且在其他浏览器上不可用。但是在 Node.js 中它是标准的函数。setInterval()setInterval是一个类似于setTimeout的函数,不同之处在于:它会在指定的特定时间间隔(以毫秒为单位)一直地运行回调函数,而不是只运行一次:setInterval() = / 每 2 秒运行一次, 2000)上面的函数每隔 2 秒运行一次,除非使用clearInterval告诉它停止(传入setInterval返回的间隔定时器 id):const id = setInterval() = / 每 2 秒运行一次, 2000)clearInterval(id)通常在setInterval回调函数中调用clearInterval,以使其自行判断是否应该再次运行或停止。 例如,此代码会运行某些事情,除非App.somethingIWait具有值arrived:const interval = setInterval() = if (App.somethingIWait = arrived) clearInterval(interval) return / 否则做些事情, 100)递归的 setTi

展开阅读全文
相关资源
相关搜索

当前位置:首页 > IT计算机/网络 > Web服务

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号