NodeJS回调地狱及Promise优化

news2024/12/22 20:09:34

    NodeJS中有很多异步API,比如常见的fs模块的readFile方法。虽然有同步的版本readFileSync, 但是其性能肯定不如前者。所以这里从异步异步版本readFile说起:

const fs = require('fs');

fs.readFile('./a.txt', 'utf-8', function(error, data) {
    if (!error) {
        console.log('a.txt data:', data);
    }
});

    函数本身比较简单,三个参数分别是文件路径,数据编码和回调函数。

    现在有这样一个需求,分别读取abc三个txt文件(文件内容分别是1, 2, 3,文件路径和js文件路径相同),按序输出文件内的内容,也就是输出1 2 3,如果并列读取,像这样:

const fs = require('fs');

fs.readFile('./a.txt', 'utf-8', function(error, data) {
    if (!error) {
        console.log('a.txt data:', data);
    }
});

fs.readFile('./b.txt', 'utf-8', function(error, data) {
    if (!error) {
        console.log('b.txt data:', data);
    }
});

fs.readFile('./c.txt', 'utf-8', function(error, data) {
    if (!error) {
        console.log('c.txt data:', data);
    }
});

多次运行,会发现每次输出的顺序不一致:

当然不止这三种,有兴趣可以多运行几次看看。

所以要出现1 2 3固定输出,得这样写,读完a.txt才能读b,读完b才能读c:

const fs = require("fs");

fs.readFile("./a.txt", "utf-8", function (error, data) {
  if (!error) {
    console.log("a.txt data:", data);
    fs.readFile("./b.txt", "utf-8", function (error, data) {
      if (!error) {
        console.log("b.txt data:", data);
        fs.readFile("./c.txt", "utf-8", function (error, data) {
          if (!error) {
            console.log("c.txt data:", data);
          }
        });
      }
    });
  }
});

    这样虽然是按序输出了,但是代码嵌套了,如果有更多文件,且读取后的处理逻辑更加复杂,整个代码的可读性就变得很差。这个就是回调地狱。为了解决这个方法,我们引入了Promise。

     Promise可以简单理解为包裹异步函数的容器,基本示例:

const fs = require("fs");

const readAPromise = new Promise(function (resolve, reject) {
  fs.readFile("./a.txt", "utf-8", function (error, data) {
    if (error) {
        reject(error);
    } else {
        resolve(data);
    }
  });
});

readAPromise.then(function(result) {
    console.log(result);
}).catch(function(error) {
    console.error(error);
});

先试试链式调用来改造回调地狱代码:

const fs = require("fs");

function readFile(filePath, defaultCoding = "utf-8") {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, defaultCoding, function (error, data) {
      if (error) {
        reject(error);
      } else {
        resolve(data);
      }
    });
  });
}

readFile("./a.txt")
  .then(function (data) {
    console.log(data);
    return readFile("./b.txt");
  })
  .then(function (data) {
    console.log(data);
    return readFile("./c.txt");
  })
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) {
    console.error(error);
  });

然后用Promise.all试试:

const fs = require("fs");

function readFile(filePath, defaultCoding = "utf-8") {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, defaultCoding, function (error, data) {
      if (error) {
        reject(error);
      } else {
        resolve(data);
      }
    });
  });
}

Promise.all([readFile("./a.txt"), readFile("./b.txt"), readFile("./c.txt")])
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) {
    console.error(error);
  });

          这里封装了一个返回文件读取结果Promise函数。然后调用Promise.all,第一个参数是个Promise对象数组。如果全部成功,就会到.then中的data去,data是各个promise resolve的结果数组,这里打印[ '1', '2', '3' ];如果有一个失败,整个Promise数组将走到.catch。要解决这个问题,可以尝试Promise.allSettled

const fs = require("fs");

function readFile(filePath, defaultCoding = "utf-8") {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, defaultCoding, function (error, data) {
        if (filePath === './b.txt') {
            reject('cannot read b file');
        }
      if (error) {
        reject(error);
      } else {
        resolve(data);
      }
    });
  });
}

Promise.allSettled([readFile("./a.txt"), readFile("./b.txt"), readFile("./c.txt")])
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) {
    console.error(error);
  });

result:

[
  { status: 'fulfilled', value: '1' },
  { status: 'rejected', reason: 'cannot read b file' },
  { status: 'fulfilled', value: '3' }
]

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

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

相关文章

目标检测理论知识

目标检测 1.基本概念 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,…

【Linux】深入理解系统文件操作(1w字超详解)

1.系统下的文件操作: ❓是不是只有C\C有文件操作呢?💡Python、Java、PHP、go也有,他们的文件操作的方法是不一样的啊 1.1对于文件操作的思考: 我们之前就说过了:文件内容属性 针对文件的操作就变成了对…

AI:43-基于深度学习的昆虫图像识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

AI:42-基于机器学习方法下以沙发为例的家具风格识别技术研究

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

【AD9361 数字接口CMOS LVDSSPI】C 并行数据 LVDS <续>

续【AD9361 数字接口CMOS &LVDS&SPI】C 并行数据之LVDS 不同于CMOS的传输方式,lvds只能工作在双端口全双工模式下。 一、 双端口全双工模式 (LVDS)代称 DFL DUAL PORT FULL DUPLEX MODE DFL 模式通过写入SPI寄存器实现。在此模式下…

html+js+css实现一个圆形滑块

htmljscss实现一个圆形滑块,可以拖动,可以点击,先看效果再讲原理,最后附上源码: 产品经理设计了这样一个需求,通过拖动圆形滑块实现时间的设置功能,虽然看着有点复杂,但是确实有点复…

vite+vue3实现 tomcat 的本地部署

背景: 很多开发小伙伴在本地开发完前端项目后,碍于服务端环境配置麻烦,想先试试在本地部署,已开发好的前端项目,由于很多文章都是文字性描述,不太直观,为了给大多数新手提供一个教程&#xff0c…

Agent 应用于提示工程

如果Agent模仿了人类在现实世界中的操作方式,那么,能否应用于提示工程即Prompt Engingeering 呢? 从LLM到Prompt Engineering 大型语言模型(LLM)是一种基于Transformer的模型,已经在一个巨大的语料库或文本数据集上进行了训练&…

ubuntu 22.04 源码安装 apollo 8.0

对于其他的关于GPU的安装包需求,这里不再列出,因为我之前安装过,偷个懒就不写了,哈哈哈哈1, 安装docker 安装docker命令(这里的安装命令都是在docker官网,还有安装包): 1, 设置docker的apt仓库 # Add Do…

论坛搭建.

目录 一.配置软件仓库 二.安装http php miriadb 三.配置数据库 一.配置软件仓库 1.进入仓库目录 cd /etc/yum.repos.d 2.创建仓库文件 vim local.repo 3.在 local.repo中写入:(粘贴的时候注意位置) [biaoshi] 仓库标识符 namemiaoshu …

【中国知名企业高管团队】系列52:魅族手机

华研荟中国手机企业的高管团队系列文章,今天介绍一个特别的存在——魅族。华研荟一度以为这个品牌被雪藏或者不再发展了,昨天在商场看到竟然开起了线下专卖店,尽管店里面门可罗雀,产品类别和数量也有限,但是仍然觉得有…

数据库连接问题 1251

Navicat连接本地数据库时出现的问题 解决办法 : 打开 输入密码 然后输入 ALTER USER ‘root’‘localhost’ IDENTIFIED WITH mysql_native_password BY ‘123456’; FLUSH PRIVILEGES;

pointNet复现、论文和代码研读

文章目录 论文复现论文研读1.动机2.模型结构![在这里插入图片描述](https://img-blog.csdnimg.cn/286bc0bfc06846f690adde4979366977.png)3.实验效果4.总结 代码研读模型什么时候保存,保存到哪里?模型训练的数据集?为什么是在CPU上运行的&…

如何在不污染代码的情况下给大R玩家定制特殊服务

点击上方亿元程序员关注和★星标 引言 大家好,我是亿元程序员,一位有着8年游戏行业经验的主程。 本系列是《和8年游戏主程一起学习设计模式》,让糟糕的代码在潜移默化中升华,欢迎大家关注分享收藏订阅。 为了在不污染代码的情况…

39基于matlab的全局路径规划算法中的快速扩展随机树RRT路径规划算法及其改进方法

基于matlab的全局路径规划算法中的快速扩展随机树RRT路径规划算法及其改进方法,RRT Star、RRT_Conncet是一种具有状态约束的非线性系统生成开环轨迹的技术,相比于其他算法可以轻松处理障碍物的问题。程序中的各参数已进行详细说明,起点坐标&a…

[ASP]青辰网络考试管理系统NES X3.5

源码下载:https://download.csdn.net/download/m0_66047725/88452220 青辰智能网络考试管理系统NES采用功能强大、高效灵活的B/S 架构模式,先进的HTML5技术作为前端开发,用户可通过PC、手机、平板等终端进行访问。具有高度的可扩展性&#x…

Mac 4款必备精品软件

一、Downie Downie 是一款万能下载器,它已经出到第 4 代了,它可以作为你的浏览器插件使用,Downie 让你几乎能够下载在网页上的一切内容。比如你在网站上看到一个很有意思的视频,看一遍不够过瘾,想要下载下来反复观看。…

上大学期间应不应该多交朋友

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

微信小程序实现微信登录(Java后台)

这两天在自己的小项目中加入了微信小程序的很多功能,今天来说一下关于微信授权登录的部分。 需要的材料 1:一个可以测试的微信小程序 2:此微信小程序的APPID和APPscret 流程 微信用户对应一个小程序都有一个唯一的openid,微信…

lv8 嵌入式开发 网络编程开发 21 私有云盘项目

目录 1云盘项目简介 2 项目实现 2.1 首先实现TCP客户端、服务端 2.2 实现客户端函数简化 2.3 实现服务端函数简化 2.4 TCP数据连包现象 2.5 封装send函数和recv函数 2.6 建立readme说明 2.7 实现文件传输 2.8 读取配置文件种的ip、端口号,通过argv[1]参数实现文件传输…