0

0

深入浅析Node.js中的异步

青灯夜游

青灯夜游

发布时间:2021-06-08 10:39:47

|

2647人浏览过

|

来源于掘金社区

转载

本篇文章给大家详细介绍一下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个阶段会在每一次的事件循环当中按照下图当中的顺序反复执行,如下图:

1.png

  • timers 阶段:这个阶段执行 timersetTimeoutsetInterval)的回调
  • I/O callbacks 阶段 :处理一些上一轮循环中的少数未执行的 I/O 回调
  • idleprepare 阶段 :仅 Node 内部使用
  • poll 阶段 :获取新的 I/O 事件, 适当的条件下 Node 将阻塞在这里
  • check 阶段 :执行 setImmediate() 的回调
  • close callbacks 阶段:执行 socketclose 事件回调

每个阶段都有一个先入先出的(FIFO)的用于执行回调的队列,事件循环运行到每个阶段,都会从对应的回调队列中取出回调函数去执行,直到队列当中的内容耗尽,或者执行的回调数量达到了最大

然后事件循环就会进入下一个阶段,然后又从下一个阶段对应的队列中取出回调函数执行,这样反复直到事件循环的最后一个阶段。而事件循环也会一个一个按照循环执行,直到进程结束。

自学 PHP、MySQL和Apache
自学 PHP、MySQL和Apache

本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第4版,经过了全面的更新、重写和扩展,包括PHP5.3最新改进的特性(例如,更好的错误和异常处理),MySQL的存储过程和存储引擎,Ajax技术与Web2.0以及Web应用需要注意的安全

下载

事件循环当中的6个宏队列和微队列的关系如下:微队列(microtask)在事件循环的各个阶段之间执行,或者说在事件循环的各个阶段对应的宏队列(macrotask)之间执行。

2.png

这里有一个特别容易混淆的版本改变:

  • 如果是 Node10 及其之前版本:宏队列当中的有几个宏任务,是要等到宏队列当中的所有宏任务全部执行完毕才会去执行微队列当中的微任务
  • 如果是 Node11 及之后版本:一旦执行一个阶段里对应宏队列当中的一个宏任务(setTimeoutsetIntervalsetImmediate 三者其中之一,不包括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)
}

异步流程控制:回调地狱、异步并发等问题

  • npmasync.js;可以通过 async.js 来控制异步流程
  • thunk:一种编程方式

Node.js 异步编程 – Promise

  • 可以通过字面意思理解,Promise 是承诺的意思;当前事件循环得不到的结果,但未来的事件循环会给到你结果
  • 它是一个状态机,状态一旦确定为 resolvedrejected 就不会改变
    • pending:初始状态,还没得到结果的状态
    • fulfilled / resolved:成功状态
    • rejected:失败状态

链式调用:.then.catch

  • resolved 状态的 Promise 会回调后面的第一个 .then
  • rejected 状态的 Promise 会回调后面的第一个 .catch
  • 任何一个 rejected 状态且后面没有 .catchPromise,都会造成浏览器/ 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)

执行 thencatch 会返回一个新 Promise,该 Promise 最终状态根据 thencatch 的回调函数的执行结果决定

  • 如果回调函数最终是 throw,该 Promiserejected 状态
  • 如果回调函数最终是 return,该 Promiseresolved 状态
  • 但如果回调函数最终 return 了一个 Promise ,该 Promise 会和回调函数 returnPromise 状态保持一致

Node.js 异步编程 – async/await

  • async functionPromise 的语法糖封装
  • 异步编程的终极方案 – 以同步的方式写异步
    • 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,一旦确定状态为 resolvedrejected 就不会改变,可以通过 .then.catch 进行链式调用。
  • async/await 以同步的方式写异步,是异步编程的终极解决方案。

更多编程相关知识,请访问:编程视频!!

相关专题

更多
node.js调试
node.js调试

node.js调试可以使用console.log()输出调试信息、断点调试和第三方调试工具。详细介绍:1、console.log()输出调试信息,通过在代码中插入console.log()语句,开发人员可以在控制台输出变量的值、函数的执行结果等信息,以便观察代码的执行流程和状态;2、断点调试,可以在代码中设置断点,以便在特定位置暂停代码的执行,观察变量的值和执行流程等。

341

2023.09.19

JavaScript 全栈开发基础(Node.js + 前端)
JavaScript 全栈开发基础(Node.js + 前端)

本专题系统介绍 JavaScript 在全栈开发中的核心知识结构,涵盖 Node.js 基础、Express/Koa 接口构建、前端交互设计、模块化与包管理、数据库连接、前后端数据通信与部署流程。通过完整项目示例,帮助学习者掌握从浏览器到服务器的一体化开发能力,实现真正意义上的全栈入门。

87

2025.11.26

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

184

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.10.25

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

505

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

240

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

246

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5202

2023.08.17

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

25

2025.12.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 7.3万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 1.9万人学习

Node.js-前端工程化必学
Node.js-前端工程化必学

共19课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号