深入浅析Node.js中的异步
本篇文章给大家详细介绍一下Node.js中的异步。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
关于 Node.js 异步,绕不开两点:非阻塞 I/O 和事件循环。也正是因为这两点,Node.js 才能被称为高性能并运用到线上环境中,那么下面来了解一下 Node.js 的异步机制和使用方式吧!【推荐学习:《nodejs 教程》】
Node.js 的非阻塞 I/O
- I/O 即
Input
/Output
,一个系统的输入和输出。 - 阻塞 I/O 和非阻塞 I/O 的区别就在于系统接收输入再到输出期间,能不能接收其他输入。
以点菜吃饭为例子:去饭堂点菜吃饭需要排队等待,在这个过程中,阿姨每次只能接待一个人,“点菜-阿姨抖勺装菜-把饭菜给到你”这个过程中阿姨并不能接收其他人的点菜,这个就是阻塞 I/O;而去餐馆点菜吃饭,去到餐馆就可以跟服务员你要吃番茄炒蛋,服务员记下来之后交给后厨,这时候来了另一桌人就把服务员招呼过去说想吃小龙虾,也就是说,在把菜给你上上来之前服务员接收了其他人的点菜,那这个就是非阻塞型 I/O。
理解非阻塞 I/O 的要点在于
-
确定一个进行
Input
/Output
的系统。 - 思考在 I/O 过程中,能不能进行其他 I/O。
那在点菜吃饭这个例子中,一个进行 Input
/Output
的系统就是点餐-后厨(阿姨)处理-上菜这样一个能让你吃上饭的系统;点餐就是 Input
,上菜就是 Output
,在这个例子中判断两者是非阻塞型还是阻塞型的关键就在于在点菜上菜这个过程中能不能接受其它的点菜上菜。就好比你点了个佛跳墙,等上菜可能就要好久了,然后来的人都是点一些简单的菜品,一分钟炒一份炒粉的那种,可能就是来来回回几波人之后都还没能给你上菜。
而 Node.js 它是用来操纵计算机的,一些如读取文件之类的操作是非常耗时的,要是不能进行其它的 I/O,那么处理效率就很会很低了,这也是 Node.js 是非阻塞型 I/O 的一个原因。
Node.js 的事件循环
Node.js 启动的时候会初始化由 libuv 提供的事件循环,每次的事件循环都包含6个阶段,这6个阶段会在每一次的事件循环当中按照下图当中的顺序反复执行,如下图:
-
timers
阶段:这个阶段执行timer
(setTimeout
、setInterval
)的回调 - I/O
callbacks
阶段 :处理一些上一轮循环中的少数未执行的 I/O 回调 -
idle
,prepare
阶段 :仅 Node 内部使用 -
poll
阶段 :获取新的 I/O 事件, 适当的条件下 Node 将阻塞在这里 -
check
阶段 :执行setImmediate()
的回调 -
close callbacks
阶段:执行socket
的close
事件回调
每个阶段都有一个先入先出的(FIFO)的用于执行回调的队列,事件循环运行到每个阶段,都会从对应的回调队列中取出回调函数去执行,直到队列当中的内容耗尽,或者执行的回调数量达到了最大。
然后事件循环就会进入下一个阶段,然后又从下一个阶段对应的队列中取出回调函数执行,这样反复直到事件循环的最后一个阶段。而事件循环也会一个一个按照循环执行,直到进程结束。
事件循环当中的6个宏队列和微队列的关系如下:微队列(microtask
)在事件循环的各个阶段之间执行,或者说在事件循环的各个阶段对应的宏队列(macrotask
)之间执行。
这里有一个特别容易混淆的版本改变:
- 如果是 Node10 及其之前版本:宏队列当中的有几个宏任务,是要等到宏队列当中的所有宏任务全部执行完毕才会去执行微队列当中的微任务
- 如果是 Node11 及之后版本:一旦执行一个阶段里对应宏队列当中的一个宏任务(
setTimeout
,setInterval
和setImmediate
三者其中之一,不包括I/O)就立刻执行微任务队列,执行完微队列当中的所有微任务再回到刚才的宏队列执行下一个宏任务。这就跟浏览器端运行一致了。
Node.js 异步编程 - callback
- 回调函数格式规范
error-first callback
node-style callback
- 第一个参数是
error
,后面的参数才是结果。
// 第一个参数是错误捕获 interview(function (err, res) { if (err) { console.log('cry') return; } console.log('smile') }) function interview(callback) { setTimeout(() => { if (Math.random() > 0.2) { callback(null, 'success') } else { callback(new Error('fail')) } }, 500) }
异步流程控制:回调地狱、异步并发等问题
npm
:async.js
;可以通过async.js
来控制异步流程thunk
:一种编程方式
Node.js 异步编程 – Promise
- 可以通过字面意思理解,
Promise
是承诺的意思;当前事件循环得不到的结果,但未来的事件循环会给到你结果 - 它是一个状态机,状态一旦确定为
resolved
或rejected
就不会改变pending
:初始状态,还没得到结果的状态fulfilled
/resolved
:成功状态rejected
:失败状态
链式调用:.then
和 .catch
resolved
状态的Promise
会回调后面的第一个.then
rejected
状态的Promise
会回调后面的第一个.catch
- 任何一个
rejected
状态且后面没有.catch
的Promise
,都会造成浏览器/ Node 环境的全局错误
// promise的状态转换以及通过then获取内容 const promise = new Promise((resolve, reject) => { setTimeout(function () { resolve(3); // reject(new Error(4)) }, 500) }) promise.then(function (result) { console.log(result) }).catch(function (err) { console.log(err) }) setTimeout(() => { console.log(promise) }, 800)
执行 then
和 catch
会返回一个新 Promise
,该 Promise
最终状态根据 then
和 catch
的回调函数的执行结果决定
- 如果回调函数最终是
throw
,该Promise
是rejected
状态 - 如果回调函数最终是
return
,该Promise
是resolved
状态 - 但如果回调函数最终
return
了一个Promise
,该Promise
会和回调函数return
的Promise
状态保持一致
Node.js 异步编程 – async
/await
async function
是Promise
的语法糖封装- 异步编程的终极方案 – 以同步的方式写异步
await
关键字可以“暂停”async function
的执行await
关键字可以以同步的写法获取Promise
的执行结果try-catch
可以获取await
所得到的错误
(async function () { await findJob() console.log('trip') })() async function findJob() { try { // 进行三轮面试 await interview(1); await interview(2); await interview(3); console.log('smile') } catch (e) { console.log('cry at ' + e.round) } } // 进行第round轮面试 function interview(round) { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() < 0.2) { const error = new Error('failed'); error.round = round; reject(error); } else { resolve('success'); } }, 500) }) }
这是一个穿越事件循环存在的 function
。
总结
- 理解非阻塞 I/O 主要在于确定一个进行 I/O 的系统,然后思考判断能不能进行其它 I/O。
- Node.js 的事件循环在 Node11 版本及之后是和浏览器的事件循环运行一致的,要注意区分。
- Node.js 异步编程的规范是第一个参数是
error
,后面的才是结果。 -
Promise
是一个状态机,初始状态为pending
,一旦确定状态为resolved
或rejected
就不会改变,可以通过.then
和.catch
进行链式调用。 -
async
/await
以同步的方式写异步,是异步编程的终极解决方案。
更多编程相关知识,请访问:编程视频!!
以上是深入浅析Node.js中的异步的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

基于无阻塞、事件驱动建立的Node服务,具有内存消耗低的优点,非常适合处理海量的网络请求。在海量请求的前提下,就需要考虑“内存控制”的相关问题了。 1. V8的垃圾回收机制与内存限制 Js由垃圾回收机

快速应用:PHP异步HTTP下载多个文件的实用开发案例分析随着互联网的发展,文件下载功能已成为很多网站和应用程序的基本需求之一。而对于需要同时下载多个文件的场景,传统的同步下载方式往往效率低下且耗费时间。为此,使用PHP异步HTTP下载多个文件成为了一种越来越常见的解决方案。本文将通过一个实际的开发案例,详细分析如何使用PHP异步HTTP

最开始的时候 JS 只在浏览器端运行,对于 Unicode 编码的字符串容易处理,但是对于二进制和非 Unicode 编码的字符串处理困难。并且二进制是计算机最底层的数据格式,视频/音频/程序/网络包

随着互联网的不断发展和普及,电子邮件已经成为了人们生活和工作中必不可少的一部分,而SMTP(SimpleMailTransferProtocol,简单邮件传输协议)则是邮件发送的重要协议之一。Swoole作为PHP的一个异步网络通讯框架,可以很好地支持异步SMTP操作,使邮件发送更加高效和稳定。本文将介绍Swoole如何支持异步SMTP操作,包括使用步

并发和异步编程并发编程处理同时执行的多个任务,异步编程是一种并发编程,其中任务不会阻塞线程。asyncio是python中用于异步编程的库,它允许程序在不阻塞主线程的情况下执行I/O操作。事件循环asyncio的核心是事件循环,它监控I/O事件并调度相应的任务。当一个协程准备就绪时,事件循环会执行它,直到它等待I/O操作。然后,它会暂停协程并继续执行其他协程。协程协程是可暂停和恢复执行的函数。asyncdef关键字用于创建协程。协程使用await关键字等待I/O操作完成。asyncio的基础以下

随着互联网业务量的不断增长,对于高并发和高性能的需求越来越高,而Swoole作为PHP的一款网络通信框架,也越来越受到开发者的青睐。其中,Swoole支持异步AMQP是比较常见的应用场景之一。那么我们来看看Swoole如何支持异步AMQP操作。首先,我们需要明确什么是AMQP。AMQP(AdvancedMessageQueuingProtocol)高级

Vue.js是一种流行的前端JavaScript框架,它提供了一种在应用程序中构建用户界面的方式。在Vue.js的文档中,我们可以找到很多有用的信息,特别是关于如何使用异步请求函数。异步请求函数是一种在应用程序中执行异步任务的方式。它们被用于从服务器获取数据、处理输入、验证表单等。一般情况下,异步请求函数需要与Promise、async和await等Java

PHP异步协程开发:加速数据缓存与读写操作在实际应用开发中,数据缓存和读写操作是常见的性能瓶颈。为了提高系统效率和用户体验,可以采用PHP异步协程技术来加速这些操作。本文将介绍PHP异步协程的基本概念和原理,并提供具体代码示例。一、异步协程的概念与原理异步协程是一种高效的并发编程技术,它利用单线程来实现轻量级的任务调度和协作。与传统的多线程或多进程并发编程相
