Node.js回调函数以及事件循环使用介绍(基础介绍 三)

回调函数

Node.js 异步编程的直接体现就是回调。

异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。

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

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

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

阻塞代码实例

创建一个文件 input.txt ,内容如下:

百度以下,你就知道

创建 main.js 文件, 代码如下:

var fs = require("fs");var data = fs.readFileSync('input.txt');console.log(data.toString());
console.log("程序执行结束!");

以上代码执行结果如下:

$ node main.js
百度以下,你就知道程序执行结束!

非阻塞代码实例

创建一个文件 input.txt ,内容如下:

百度以下,你就知道

创建 main.js 文件, 代码如下:

var fs = require("fs");fs.readFile('input.txt', function (err, data) {if (err) return console.error(err);console.log(data.toString());
});console.log("程序执行结束!");

以上代码执行结果如下:

$ node main.js
程序执行结束!
百度以下,你就知道

以上两个实例我们了解了阻塞与非阻塞调用的不同。第一个实例在文件读取完后才执行完程序。 第二个实例我们呢不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。

因此,阻塞按是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

 事件循环

Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。

Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.


事件驱动程序

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

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

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

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

整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

以下程序绑定事件处理程序:

// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);

我们可以通过程序触发事件:

// 触发事件
eventEmitter.emit('eventName');

实例

创建 main.js 文件,代码如下所示:

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();// 创建事件处理程序
var connectHandler = function connected() {console.log('连接成功。');// 触发 data_received 事件 eventEmitter.emit('data_received');
}// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){console.log('数据接收成功。');
});// 触发 connection 事件 
eventEmitter.emit('connection');console.log("程序执行完毕。");

接下来让我们执行以上代码:

$ node main.js
连接成功。
数据接收成功。
程序执行完毕。

Node 应用程序是如何工作的?

在 Node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

接下来让我们来重新看下前面的实例,创建一个 input.txt ,文件内容如下:

百度一下,你就知道

创建 main.js 文件,代码如下:

var fs = require("fs");fs.readFile('input.txt', function (err, data) {if (err){console.log(err.stack);return;}console.log(data.toString());
});
console.log("程序执行完毕");

以上程序中 fs.readFile() 是异步函数用于读取文件。 如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。

如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。

执行以上代码,执行结果如下:

程序执行完毕
百度以下,你就知道

接下来我们删除 input.txt 文件,执行结果如下所示:

程序执行完毕
Error: ENOENT, open 'input.txt'

因为文件 input.txt 不存在,所以输出了错误信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/4983.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux系列-进程的属性

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 我们上一篇文章当中讲到了进程的概念,我们知道进程信息是放到一个tast_struct的结构体当中的,这个结构体也叫做PCB。 PCB是内存级的操作,我们…

PLC单键启停控制的多种写法

题目:编写程序,实现当按下SB1按钮奇数次,灯亮;当按下SB1按钮偶数次,灯灭,即单键启停控制,设计梯形图。 解法一:使用标志位进行自锁互锁 (1)刚上电&#xff0c…

PH热榜 | 2024-11-06

DevNow 是一个精简的开源技术博客项目模版,支持 Vercel 一键部署,支持评论、搜索等功能,欢迎大家体验。 Github:https://github.com/LaughingZhu/DevNow 1. MindOne Builder 标语:这是一个“设计优先”的应用构建工具…

11.6 校内模拟赛总结

打的很顺的一场 复盘 7:40 开题,看到题目名很interesting T1 看起来很典,中位数显然考虑二分,然后就是最大子段和;T2 构造?一看数据范围这么小,感觉不是很难做;T3 神秘数据结构;T…

SpringBoot健康监控

文章目录 1_监控-健康监控服务2_监控-Admin可视化3_使用介绍 1_监控-健康监控服务 目的:能够理解健康监控actuator的作用 讲解: 每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景…

时间序列算法---ARIMA

时间序列其他相关参考文章: 时间序列分类任务—tsfresh库 时间序列预测—Prophet python时间序列处理 有季节效应的非平稳序列分析   现代时间序列分析方法主要有两个不同的方向:一个方向是由外向内的分析视角产生的方法是与确定性因素分解相关的方法&…

Java内存模型

Java内存模型 JMM即java memory model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。 JMM体现在以下几个方面 原子性 - 保证指令不受到线程上下文切换的影响(之前的synchornized原理文章有介绍过) 可见性 - 保证指令不会受CPU缓…

软考高级架构 - 8.2 - 系统架构评估 - 超详细讲解+精简总结

8.2-系统架构评估 系统架构评估就是对系统架构的质量进行分析,以便帮助设计者作出架构决策,确保系统能够符合需求。评估方法大致分为三种: 基于问卷或检查表:通过设计好的问卷或清单,收集开发人员和相关人员的…

【LLM】Generative Agents和代码实践

note Generative Agents是2023年斯坦福提出的agent小镇,通过memory->reflection->planning的框架提高NPC的行为目标性,给游戏NPC的灵活设计带来了可能。Generative Agents是一种多智能体交互的框架,它模拟现实中的人类行为。这些Agent…

K. Farm Management 【CCPC2024哈尔滨站】

K. Farm Management 思路: 很容易想到的策略: 给每个作物都安排最短的时长 l l l,剩下的时间作为可支配时间。选择删除收益最高的作物,然后将尽可能多的可支配时间用于这个作物。或者选择删除收益低时间还长的作物,然后将时间解…

智能 ODN 系统研究与设计

智能 ODN 系统研究与设计 摘 要:为了解决ODN面临的光纤错综复杂,故障定位低效等问题,引入电子标签,智能OTDR技术,提出了一种基于电子标签、光纤检测笔和智能OTDR故障监测的智能 ODN 解决方案,并重点讲述了智能ODN系统的…

Openlayers实现长度测量

概述 在 Openlayers 中,计算两点之间的距离,通常会用到ol/sphere模块。ol/sphere模块主要用于处理与球体(特别是地球球体)相关的数学和几何计算。而长度测量主要用到ol/sphere中的getDistance函数。 getDistance函数用于计算地球表面两点之间的距离,通常用于经纬度坐标。…

xftp连接中不成功 + sudo vim 修改sshd_config不成功的解决方法

我们使用sudo vim不成功,但是我们使用sudo su就可以 了! root用户权利更大! 喵的,终于成功了,一个xftp连接半天不成功。(添加上面的内容就可以连接成功了↑)

常用的c++特性-->day02

可调用对象 案例 #include <iostream> #include <string> #include <vector> using namespace std;using funcptr void(*)(int, string);int print(int a, double b) {cout << a << ", " << b << endl;return 0; } // …

应急车道占用检测算法的技术方案与应用

应急车道是高速公路上的生命通道&#xff0c;专门用于救护车、消防车、警车等紧急车辆通行&#xff0c;帮助应对突发状况。然而&#xff0c;一些驾驶员出于各种原因违规占用应急车道&#xff0c;阻碍救援车辆的正常通行&#xff0c;导致交通救援效率大幅下降&#xff0c;甚至加…

卡尔曼滤波算法Kalman filter algorithm

一、假如 状态向量服从高斯分布&#xff1a; 而且状态转移是线性的&#xff1a; 测量是状态的线性关系&#xff08;带噪声&#xff09; 初始状态的置信度也是正态分布 二、卡尔曼滤波的算法流程为 疑问&#xff1a;多测量融合&#xff0c;是不是用不同的传感器测量值去重复5…

java_继承

1.为啥用 继承? Pupil类 package com.hspedu.extend;// 小学生->模拟小学生考试的情况 public class Pupil {public String name;public int age;private double score;public void setScore(double score) {this.score score;}public void testing() {System.out.printl…

Redis 缓存击穿

目录 缓存击穿 什么是缓存击穿&#xff1f; 有哪些解决办法&#xff1f; 缓存穿透和缓存击穿有什么区别&#xff1f; 缓存雪崩 什么是缓存雪崩&#xff1f; 有哪些解决办法&#xff1f; 缓存预热如何实现&#xff1f; 缓存雪崩和缓存击穿有什么区别&#xff1f; 如何保…

【Redis的安装以及主从复制的搭建】配置Redis的哨兵模式

文章目录 一、安装Redis1、上传、解压、重命名2、安装GCC环境3、编译源码4、进行安装5、修改配置文件redis.conf 二、Redis主从复制搭建1、创建文件夹用来实现主从复制 三、配置Redis的哨兵模式1、创建文件夹2、修改sentinel.conf配置文件3、启动 一、安装Redis 1、上传、解压…

WPF中的转换器

单值转换器 1.创建项目后下载两个NuGet程序包 2.先定义一个转换器实现IValueConverter接口 using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; usin…