zoukankan      html  css  js  c++  java
  • Node.js 阻塞式IO与非阻塞式IO与错误处理

    2019-12-16

    13:20:53

     1.1 一个典型的 Node Web 应用程序

    大体上来说,Node 和 JavaScript 的优势之一是它们的单线程编程模型。多个线程一般会引入 bug,尽管一些新的编程语言,包括 Go 和 Rust,试图提供更加安全的并发工具,但 Node 仍然保 留了 JavaScript 在浏览器中所用的模型。在为浏览器编写代码时,我们写的指令序列一次执行一 条,代码不是并行执行的。然而对于用户界面来说,这样是不合理的:没有哪个用户想在浏览器 执行网络访问或文件获取这样的低速操作时干等着。为了解决这个问题,浏览器引入了事件机制:在你点击按钮时,就有一个事件被触发,还有一个之前定义的函数会跑起来。这种机制可以规避 一些在线程编程中经常出现的问题,比如资源死锁和竞态条件

    1.1.1 非阻塞 I/O

    那么在服务器端编程中,这有什么意义呢?其实服务器端编程面对的情况也差不多:访问磁 盘和网络这样的 I/O 请求会比较慢,所以我们希望,在读取文件或通过网络发送消息时,运行平 台不会阻塞业务逻辑的执行。Node 用三种技术来解决这个问题:事件、异步 API、非阻塞 I/O。 在 Node 程序员看来,非阻塞 I/O 是个底层术语。它的意思是说,你的程序可以在做其他事情时 发起一个请求来获取网络资源,然后当网络操作完成时,将会运行一个回调函数来处理这个操作 的结果。 图 1-1 展示了一个典型的 Node Web 应用程序,它用 Web 应用库 Express 来处理商店的订单 流程。为了购买产品,浏览器发起了一个请求,然后应用程序检查库存,为该用户创建一个账号, 发回执邮件,并返回一个 JSON HTTP 响应给浏览器。同时在做的其他事情有:发送了一封回执 邮件,更新了数据库来保存用户的详细信息和订单。代码本身很简单,就是 JavaScript 指令,但 运行平台是并发操作的,因为它用了非阻塞 I/O。

     在图 1-1 中,数据库是通过网络访问的。Node 中的网络访问是非阻塞的,它用了一个名为libuv 的库来访问操作系统的非阻塞网络调用。这个库在 Linux、macOS 和 Windows 中的实现是 不同的,但不用担心,因为你只需要会用操作数据库的 JavaScript 库就可以了。只要写一些 db.insert(query, err => {})这样的代码,Node 就会帮你完成那些经过高度优化的非阻塞 网络操作。

    访问硬盘也差不多,但又不完全一样。在生成了回执邮件并从硬盘中读取邮件模板时,libuv 借助线程池模拟出了一种使用非阻塞调用的假象。管理线程池是个苦差事,相较而言, email.send('template.ejs', (err, html) => {})这样的代码肯定要容易理解得多了。 在进行速度较慢的处理时让 Node 能做其他事情,是使用带非阻塞 I/O 的异步 API 真正的好 处。即便你只有一个单线程、单进程的 Node Web 应用,它也可以同时处理上千个网站访客发起 的连接。要想知道 Node 是如何做到的,得先研究一下事件轮询。

    1.4.2 核心模块

    Node 的核心模块就相当于其他语言的标准库,它们是编写服务器端 JavaScript 所需的工具。 大多数服务器端开发人员都知道,JavaScript 标准本身没有任何处理网络的东西,甚至连处理文 件 I/O 的东西都没有。Node 以最少的代码给它加上了文件和 TCP/IP 网络功能,使其成为了一个 可用的服务器端编程语言。 1. 文件系统 Node 不仅有文件系统库(fs、path)、TCP 客户端和服务端库(net)、HTTP 库(http 和 https) 和域名解析库(dns),还有一个经常用来写测试的断言库(assert),以及一个用来查询平台信息 的操作系统库(os)。 Node 还有一些独有库。事件模块是一个处理事件的小型库,Node 的大多数 API 都是以它为 基础来做的。比如说,流模块用事件模块提供了一个处理流数据的抽象接口。因为 Node 中的所 有数据流用的都是同样的 API,所以你可以很轻松地组装出软件组件。如果你有一个文件流读取 器,就可以很方便地把它跟压缩数据的 zlib 连接到一起,然后这个 zlib 再连接一个文件流写入器, 从而形成一个文件流处理管道。 在下面这段代码中,我们用 Node 的 fs 模块创建了读和写流,然后把它们通过另外一个流

     

    index.js:

    require('colors');
    console.log('smashing node'.rainbow);

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    function c(){
        b();
    };
    function b(){
        a();
    };
    function a(){
        throw new Error('here');
    };
    c();

    function c(){
        b();
    };
    function b(){
        a();
    };
    function a(){
        setTimeout(function(){
            throw new Error('here');
        },10);
    };
    c();

     

     

     

  • 相关阅读:
    Effective Java 第三版——26. 不要使用原始类型
    Effective Java 第三版——25. 将源文件限制为单个顶级类
    Effective Java 第三版——24. 优先考虑静态成员类
    Effective Java 第三版——23. 优先使用类层次而不是标签类
    Effective Java 第三版——22. 接口仅用来定义类型
    Effective Java 第三版——21. 为后代设计接口
    Effective Java 第三版——20. 接口优于抽象类
    Effective Java 第三版——19. 如果使用继承则设计,并文档说明,否则不该使用
    Effective Java 第三版——18. 组合优于继承
    Effective Java 第三版——17. 最小化可变性
  • 原文地址:https://www.cnblogs.com/JasonPeng1/p/12049787.html
Copyright © 2011-2022 走看看