• 【NodeJs-5天学习】第一天篇④ ——了解NodeJs回调函数和事件驱动机制


    面向读者群体

    • ❤️ 电子物联网专业同学,想针对硬件功能构造简单的服务器,不需要学习专业的服务器开发知识 ❤️
    • ❤️ 业余爱好物联网开发者,有简单技术基础,想针对硬件功能构造简单的服务器❤️

    技术要求

    • HTMLCSSJavaScript基础更好,当然也没事,就直接运行实例代码学习

    专栏介绍

    • 通过简短5天时间的渐进式学习NodeJs,可以了解到基本的服务开发概念,同时可以学习到npm、内置核心API(FS文件系统操作、HTTP服务器、Express框架等等),最终能够完成基本的web开发,而且能够部署到公网访问。

    学习交流群

    • NodeJs物联网五天入门学习之旅(搜索:729040020

    🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请留言轰炸哦!及时修正!感谢支持!🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝

    1、Node.js 中的回调(Callback)函数

    回调定义:将一个函数A作为参数传递给函数B,在函数B内对函数A进行调用,函数A就是回调函数

    Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。 而回调的使用在NodeJs上集中于它本身的异步编程

    Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。如果我们使用了同步,假设有一个处理耗时非常长,那么其他操作就必须阻塞等待它完成,这在服务开发中属于严重性能问题。

    • 非必要不使用同步接口。
    • 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。

    回调函数一般作为函数的最后一个参数出现:

    function foo1(name, age, callback) { }
    function foo2(value, callback1, callback2) { }
    
    • 1
    • 2

    例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。

    const fs = require('fs');
    //异步读取文件 的内容(回调函数)
    fs.readFile('demo.txt',function (err,data){
        if(err){
            console.log(err);    //输出错误信息
        }
        console.log(data.toString());    //输出文件内容
    })
    
    //3、主程序流程结束
    console.log("node程序已经执行结束")
    
    //node程序已经执行结束
    //文件内容
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • fs就是操作文件系统的内置库。

    2、Nodejs事件循环模型

    讲完回调,就得说说NodeJs的事件驱动机制,并且这两者是密不可分。

    2.1 浅析事件驱动

    Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。

    当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。

    这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)

    在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数

    在这里插入图片描述

    2.2 深入NodeJs事件驱动

    参考文献:

    下面是一张 Node.js 早期的架构图,来自 Node.js 之父 Ryan Dahl 的演讲稿,在今天依然不过时,它简要的介绍了 Node.js 是基于 Chrome V8引擎构建的,

    • 事件循环(Event Loop)分发 I/O 任务
    • 最终工作线程(Work Thread)将任务丢到线程池(Thread Pool)里去执行
    • 事件循环只要等待执行结果就可以了。

    在这里插入图片描述

    • Chrome V8 是 Google 发布的开源 JavaScript 引擎,采用 C/C++ 编写,在 Google 的 Chrome 浏览器中被使用。Chrome V8 引擎可以独立运行,也可以用来嵌入到 C/C++ 应用程序中执行。
    • Event Loop 事件循环(由 libuv 提供)
    • Thread Pool 线程池(由 libuv 提供)

    梳理一下

    • Chrome V8 是 JavaScript 引擎
    • Node.js 内置 Chrome V8 引擎,所以它使用的 JavaScript 语法
    • JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事
    • 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
    • 如果排队是因为计算量大,CPU 忙不过来,倒也算了,但是很多时候 CPU 是闲着的,因为 I/O 很慢,不得不等着结果出来,再往下执行
    • CPU 完全可以不管 I/O 设备,挂起处于等待中的任务,先运行排在后面的任务
    • 将等待中的 I/O 任务放到 Event Loop
    • 由 Event Loop 将 I/O 任务放到线程池
    • 只要有资源,就尽力执行

    从底层代码实现来看,

    在这里插入图片描述

    梳理一下

    • Chrome V8 解释并执行 JavaScript 代码(这就是为什么浏览器能执行 JavaScript 原因)
    • libuv 由事件循环和线程池组成,负责所有 I/O 任务的分发与执行
    • 在Node.js Bindings层做的事儿就是将 Chrome V8 等暴露的 C/C++ 接口转成JavaScript Api,并且结合这些 Api 编写了 Node.js 标准库,所有这些 Api 统称为 Node.js SDK

    我们在写代码的时候,由 Event Loop 来接受处理,而真正执行操作的是具体的线程池里的 I/O 任务。之所以说 Node.js 是单线程,就是因为在接受任务的时候是单线程的,它无需进程/线程切换上下文的成本,非常高效,但它在执行具体任务的时候是多线程的。

    举个例子:

    • 快递仓库有一条传送带(Event Loop),源源不断把快递传送过来,两边的工人Thread Pool)不断分拣装车派发到全国各地。

    3、总结

    篇④主要讲解了一下回调函数的定义以及NodeJs中经典的事件驱动模型(特别是单线程性能)。当然,对于初学者不理解也没有问题,先有个概念。

    思考:

    • 如果要实现多线程操作怎么办?
  • 相关阅读:
    嵌入式软件常用测试工具
    【Linux Socket C++】为什么IO复用需要用到非阻塞IO?EAGAIN的简单介绍与应用
    【MFC】 前言(1)
    iframe渲染后端接口文件和实现下载功能
    使用QT实现http里面的get和post
    Re 爬取数据
    中级工程师的职称好评吗?怎么评中级工程师?需要什么材料?
    基于ASP.NET的网上驾校管理系统设计与实现
    GIS理论基础
    B. Box
  • 原文地址:https://blog.csdn.net/weixin_44614230/article/details/126413038