二、Promise

news2024/11/15 22:46:33

Promise

  • 1、回调地狱
    • 1.1 如何解决回调地狱的问题
    • 1.2 Promise 的基本概念
  • 2、基于回调函数按顺序读取文件内容
  • 3. 基于 then-fs 读取文件内容
    • 3.1 then-fs 的基本使用
    • 3.2 .then() 方法的特性
    • 3.3 基于 Promise 按顺序读取文件的内容
    • 3.4 通过 .catch 捕获错误
    • 3.4 通过 .catch 捕获错误
    • 3.5 Promise.all() 方法
    • 3.6 Promise.race() 方法
  • 4. 基于 Promise 封装读文件的方法
    • 4.1 getFile 方法的基本定义
    • 4.2 创建具体的异步操作
    • 4.3 获取 .then 的两个实参
    • 4.4 调用 resolve 和 reject 回调函数

1、回调地狱

多层回调函数的相互嵌套,就形成了回调地狱。示例代码如下:

setTimeout(() => { //第 1 层回调函数
    console.log('延时 1 秒后输出')

    setTimeout(() => { //第 2 层回调函数
        console.log('再延时 2 秒后输出')

        setTimeout(() => { // 第 3 层回调函数
            console.log('再延时 3 秒后输出')

        }, 3000)
    }, 2000)
}, 1000)

在这里插入图片描述

回调地狱的缺点:

  • 代码耦合性太强,牵一发而动全身,难以维护
  • 大量冗余的代码相互嵌套,代码的可读性变差

1.1 如何解决回调地狱的问题

为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念。

1.2 Promise 的基本概念

① Promise 是一个构造函数

  • 我们可以创建 Promise 的实例 const p = new Promise()
  • new 出来的 Promise实例对象,代表一个异步操作

② Promise.prototype 上包含一个 .then() 方法

  • 每一次 new Promise() 构造函数得到的实例对象,
  • 都可以通过原型链的方式访问到 .then() 方法,例如 p.then()

③ .then() 方法用来预先指定成功和失败的回调函数

  • p.then( 成功的回调函数,失败的回调函数)
  • p.then( result => { }, error => { })
  • 调用 .then() 方法时,成功的回调函数是必选的、失败的回调函数是可选的

2、基于回调函数按顺序读取文件内容

  1. 在 package.json 的根节点中添加 “type”: “module” 节点
  2. 在项目根目录输入 npm init -y
  3. 在生成的package.json 根节点中添加 "type":"module",
  4. 新建flies文件夹,并在文件夹下新建1.txt2.txt3.txt三个文件,内容分别为111,222,333
  5. 新建文件02m.js并调用 node .\02m.js运行

在这里插入图片描述

在这里插入图片描述

import fs from 'fs'

//读取文件1.txt
fs.readFile('./files/1.txt', 'utf8', (err1, r1) => {
    if (err1) return console.log(err1.message) //读取文件1失败
    console.log(r1) //读取文件1成功
    //读取文件2.txt
    fs.readFile('./files/2.txt', 'utf8', (err2, r2) => {
        if (err2) return console.log(err2.message) //读取文件2失败
        console.log(r2) //读取文件2成功
        //读取文件3. txt
        fs.readFile('./files/3.txt', 'utf8', (err3, r3) => {
            if (err3) return console.log(err3.message)  //读取文件3失败
            console.log(r3) //读取文件3成功
        })
    })
})

在这里插入图片描述

3. 基于 then-fs 读取文件内容

由于 node.js 官方提供的 fs 模块仅支持回调函数的方式读取文件,不支持Promise 的调用方式。因此,需要先运行如下的命令,安装 then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容:

npm install then-fs

在这里插入图片描述

3.1 then-fs 的基本使用

调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此可以调用 .then() 方法为每个 Promise 异步操作指定成功失败之后的回调函数。示例代码如下:
注意:上述的代码无法保证文件的读取顺序,需要做进一步的改进!

/** 
 *  基于Promise的方式读取文件
 */

import thenFs from 'then-fs'

// 注意 .then()中失败的回调函数是可选的,可以被省略
thenFs.readFile('./files/1.txt', 'utf8').then(r1 => { console.log(r1); }, err1 => { console.log(err1.message); })
thenFs.readFile('./files/2.txt', 'utf8').then(r2 => { console.log(r2); }, err2 => { console.log(err2.message); })
thenFs.readFile('./files/3.txt', 'utf8').then(r3 => { console.log(r3); }, err3 => { console.log(err3.message); })

l两次调用读取文件的顺序不同,无法保障读取顺序
两次调用读取文件的顺序不同,无法保障读取顺序

3.2 .then() 方法的特性

如果上一个 .then() 方法中返回了一个新的Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通过 .then() 方法的链式调用,就解决了回调地狱的问题。

3.3 基于 Promise 按顺序读取文件的内容

Promise 支持链式调用,从而来解决回调地狱的问题。示例代码如下:

import thenFs from "then-fs";

thenFs.readFile('./files/1.txt', 'utf8') //1.返回值是Promise的实例对象
    .then(r1 => { //2.通过 .then 为第一个 Promise 实例指定成功之后的回调函数
        console.log(r1);
        return thenFs.readFile('./files/2.txt', 'utf8') //3.在第一个 .then 中返回一个新的 Promise 实例对象
    })
    .then(r2 => {  // 4. 继续调用 .then 为上一个 .then 的返回值(新的 Promise 实例)指定成功之后的回调函数
        console.log(r2);
        return thenFs.readFile('./files/3.txt', 'utf8') // 5. 在第二个 .then 中再返回一个新的Promise 实例对象
    })
    .then(r3 => {  // 6.继续调用 .then 为上一个 .then  的返回值( 新的 Promise 实例) 指定成功之后的回调函数
        console.log(r3);
    })

3.4 通过 .catch 捕获错误

在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理:

import thenFs from "then-fs";

thenFs.readFile('./files/11.txt', 'utf8') //文件不存在导致读取失败,后面的3个 .then 都不执行
    .then(r1 => {
        console.log(r1);
        return thenFs.readFile('./files/2.txt', 'utf8')
    })
    .then(r2 => {
        console.log(r2);
        return thenFs.readFile('./files/3.txt', 'utf8')
    })
    .then(r3 => {
        console.log(r3);
    })
    .catch(err => { // 捕获第一行发生的错误,并输出错误信息
        console.log(err.message);
    })

3.4 通过 .catch 捕获错误

如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将.catch 的调用提前,示例代码如下:

import thenFs from "then-fs";

thenFs.readFile('./files/11.txt', 'utf8')
    .catch(err => {                // 捕获第 1 行 发生的错误,并输出错误的信息
        console.log(err.message);  // 由于错误已经被及时处理,不影响后续 .then 的正常执行
    })
    .then(r1 => {
        console.log(r1);   // 输出 undefined
        return thenFs.readFile('./files/2.txt', 'utf8')
    })
    .then(r2 => {
        console.log(r2);  //输出 222
        return thenFs.readFile('./files/3.txt', 'utf8')
    })
    .then(r3 => {
        console.log(r3);  //输出 333
    })

3.5 Promise.all() 方法

Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then 操作(等待机制)。示例代码如下:
注意:数组中 Promise 实例的顺序,就是最终结果的顺序!

import thenFs from "then-fs";
// 1.定义一个数组,存放三个读取文件的异步操作
const promiseArr = [
    thenFs.readFile('./files/11.txt', 'utf8'),
    thenFs.readFile('./files/2.txt', 'utf8'),
    thenFs.readFile('./files/3.txt', 'utf8'),
]

// 2.将 Promise 的数组,作为 Promise.all()的参数
Promise.all(promiseArr)
    .then(([r1, r2, r3]) => {  // 2.1 所有文件读取成功(等待机制)
        console.log(r1, r2, r3);
    })
    .catch(err => {  // 2.2 捕获 Promise 异步操作中的错误
        console.log(err.message);
    })

3.6 Promise.race() 方法

Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)。示例代码如下:

import thenFs from "then-fs";
// 1.定义一个数组,存放三个读取文件的异步操作
const promiseArr = [
    thenFs.readFile('./files/1.txt', 'utf8'),
    thenFs.readFile('./files/2.txt', 'utf8'),
    thenFs.readFile('./files/3.txt', 'utf8'),
]

// 2.将 Promise 的数组,作为 Promise.arce()的参数
Promise.race(promiseArr)
    .then((r) => {  // 2.1 只要任何一个异步操作完成,就立即执行成功的回调函数(赛跑机制)
        console.log(r);
    })
    .catch(err => {  // 2.2 捕获 Promise 异步操作中的错误
        console.log(err.message);
    })

4. 基于 Promise 封装读文件的方法

方法的封装要求:
① 方法的名称要定义为 getFile
② 方法接收一个形参 fpath,表示要读取的文件的路径
③ 方法的返回值为 Promise 实例对象

4.1 getFile 方法的基本定义

注意:第 5 行代码中的 new Promise() 只是创建了一个形式上的异步操作。

// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath,表示要读取的文件的路径
function getFile(fpath) {
    // 3.方法的返回值是 Promise 的实例对象
    return new Promise()
}

在这里插入图片描述

4.2 创建具体的异步操作

如果想要创建具体的异步操作,则需要在new Promise() 构造函数期间,传递一个function 函数,将具体的异步操作定义到 function 函数内部。示例代码如下:

// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath,表示要读取的文件的路径
function getFile(fpath) {
    // 3.方法的返回值是 Promise 的实例对象
    return new Promise(function () {
        // 4.下面这行代码,表示这是一个具体的、读取文件的异步操作
        fs.readFile(fpath, 'utf8', (err, dataStr) => { })
    })
}

4.3 获取 .then 的两个实参

通过 .then() 指定的成功失败的回调函数,可以在 function 的形参中进行接收,示例代码如下:

// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath,表示要读取的文件的路径
function getFile(fpath) {
    // 3.方法的返回值是 Promise 的实例对象
        //resolve 形参是:调用getFile() 方法时,通过 .then 指定的 "成功的" 回调函数 
        //reject  形参是:调用getFile() 方法时,通过 .then 指定的 "失败的" 回调函数 
    return new Promise(function (resolve,reject) {
        // 4.下面这行代码,表示这是一个具体的、读取文件的异步操作
        fs.readFile(fpath, 'utf8', (err, dataStr) => { })
    })
}

// getFile 方法的调用过程
getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)

4.4 调用 resolve 和 reject 回调函数

Promise 异步操作的结果,可以调用 resolvereject 回调函数进行处理。示例代码如下:

// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath,表示要读取的文件的路径
function getFile(fpath) {
    // 3.方法的返回值是 Promise 的实例对象
    //resolve 形参是:调用getFile() 方法时,通过 .then 指定的 "成功的" 回调函数 
    //reject  形参是:调用getFile() 方法时,通过 .then 指定的 "失败的" 回调函数 
    return new Promise(function (resolve, reject) {
        // 4.下面这行代码,表示这是一个具体的、读取文件的异步操作
        fs.readFile(fpath, 'utf8', (err, dataStr) => {
            if (err) return reject(err)  //如果读取失败,则调用"失败的回调函数"
            resolve(dataStr)            //如果读取成功,则调用"成功的回调函数"
        })
    })
}

// getFile 方法的调用过程
getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
import fs from 'fs'
// 1.方法的名称为 getFile
// 2.方法接收一个形参 fpath,表示要读取的文件的路径
function getFile(fpath) {
    // 3.方法的返回值是 Promise 的实例对象
    //resolve 形参是:调用getFile() 方法时,通过 .then 指定的 "成功的" 回调函数 
    //reject  形参是:调用getFile() 方法时,通过 .then 指定的 "失败的" 回调函数 
    return new Promise(function (resolve, reject) {
        // 4.下面这行代码,表示这是一个具体的、读取文件的异步操作
        fs.readFile(fpath, 'utf8', (err, dataStr) => {
            if (err) return reject(err)  //如果读取失败,则调用"失败的回调函数"
            resolve(dataStr)            //如果读取成功,则调用"成功的回调函数"
        })
    })
}

// getFile 方法的调用过程
// getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
getFile('./files/1.txt').then(r => { console.log(r); }, err => { console.log(err.message); })
getFile('./files/12.txt').then(r => { console.log(r); }, err => { console.log(err.message); })

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

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

相关文章

基于RBAC权限控制模型的管理系统的设计与实现

文章目录一、RBAC 权限设计1.1 模型概述1.2 模型分类二、基于RBAC的后台管理系统2.1 项目概述2.2 技术选型2.3 内部处理流程2.4 功能模块展示2.5 权限控制展示2.6 下载说明一、RBAC 权限设计 1.1 模型概述 基于角色的访问控制 RBAC,是实施面向企业安全策略的一种有…

kafka的介绍和基本使用

文章目录Kafka介绍1.Kafka的使用场景2.Kafka基本概念kafka基本使用1.安装前的环境准备2.启动kafka服务器3.创建主题topic4.发送消息5.消费消息Kafka介绍 Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的 &…

载波相位误差对BPSK解调性能的影响理论推导

在上一篇博客基础上,继续讨论载波相位误差对解调性能的影响! 【通信原理】通信原理书中解调器输入端信噪比a2/(2σ2)与比特信噪比Eb/No有什么关系? 以BPSK为例,从解调原理图可以看出,当本地参考载波信号与原始载波存在相位误差时,假设相位差为 φ \varphi φ,则解调器低…

【Linux】了解磁盘/文件系统/inode

文章目录一.磁盘1.磁盘的结构2.磁盘的定位(寻找方案)3.磁盘的分区与格式化介绍二.理解inode三.ext2文件系统的存储方案一.磁盘 1.磁盘的结构 问题1:什么是磁盘? 磁盘是在冯诺依曼体系结构中几乎唯一的机械设备,机械设…

AntDB数据库助力中国移动结算中心建设

为响应中国移动集团公司IT集中化的要求:全面落实“十三五”十大战略工程,加快“推动公司IT资源一体化整合“重点专项工作。以IT系统为载体,构建高效运营支撑体系,形成集中化支撑和协同业务支撑模式,打造极致体验、高效…

列表初始化(内置类型、自定义类型)

列表初始化的特性来源于单参数的隐式类型转换。以下面这个赋值为例,我们可以理解成 先创建一个匿名对象Point(2),这个时候就变成了 Point p Point(2);然后会调用拷贝构造。 虽然隐式转换的可以这样理解,但是最后会被编译器优化成直接调用有…

[Android]Bitmap Drawable

在实际开发中&#xff0c;我们可以直接引用原始的图片&#xff0c;但是也可以通过xml的方式来描述它&#xff0c;通过xml来描述的BitmapDrawable可以设置更多效果。 <?xml version"1.0" encoding"utf-8"?> <bitmap xmlns:android"http://…

java spring IOC Bean管理操作讲解 并代码演示xml的实现方式

查看本文 需要您使用spring创建过对象管理 如果之前没有接触过 可以先查看我的文章 java 手把手带你创建一个spring入门案例 IOC 操作中 Bean管理主要有两个部分 分别是创建对象和注入属性 他们都有两种实现方式 分别是xml和注解方式实现 本文只演示xml 后续我会出注解方式的文…

第十三届蓝桥杯省赛 JAVA A组 - 蜂巢

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;蜂巢 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥别的小伙伴整理常考算法题解&#xff0c;祝大家都能…

背包问题——“0-1背包”,“完全背包”(这样讲,还能不会?)

目录 一、0-1背包 1.1、0-1背包解决的问题 1.2、dp数组定义 1.3、转移方程 1.3.1、二维dp数组 1.3.2、一维dp数组 1.4、遍历顺序 1.5、测试代码 1.6、练习 二、完全背包 2.1、完全背包解决问题 2.2、与0-1背包的区别 2.3、测试代码 2.4、拓展问题&#xff1a;装满…

【2022】13 年终总结

新年Flag 2023年&#xff0c;为了各方面能有所进步&#xff0c;列一些希望达成的目标和想做的事&#xff0c;到年底看看效果。 撰写一篇英文论文 申请到CSC 和xl去外地玩两次 想到了再加 去年Flag倒了几个&#xff1f; 一维河网水动力学模型导师说不用自己编&#xff0c;看懂…

Numpy文件交互:.npy和.npz有什么区别?

文章目录saveloadsavezsavez_compressedNumpy提供了以.npy为后缀的文件存储方案&#xff0c;与这种文件格式密切相关的读、写函数分别是np.load和np.save。通过savez可以一次性存储多个数组&#xff0c;并可通过load以键值对的形式读取出来&#xff1b;如果觉得文件太大&#x…

Mybatis缓存

内存中的一块存储空间&#xff0c;服务于某个应用程序&#xff0c;旨在将频繁读取的数据临时保存在内存中&#xff0c;便于二次快速访问。 一级缓存 SqlSession级别的缓存&#xff0c;同一个SqlSession的发起多次同构查询&#xff0c;会将数据保存在一级缓存中。 注意&#x…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(频率特性测试仪)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;频率特性测试仪 &#x1f34a;&#x1f34a;1.“模式”选项组 &#x1f34a;&#x1f34a;2.“水平”选项组 &#x1f34a;&#x1f34a;3.“垂直”选项组 &#x1f34a;&#x1f34a;4.“控件”选项组 序言 N…

SpringBoot+Vue项目大学生租房平台

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…

数据结构课程设计[2023-01-19]

数据结构课程设计[2023-01-19] 数据结构课程设计 一、课程设计要求 实现指定的题目&#xff08;学号最后两位%41&#xff09;&#xff0c;并撰写课程设计报告。独立完成&#xff0c;功能不完备也没关系&#xff0c;只要是自己做的 使用 C、C或者 JAVA 语言&#xff0c;采用…

​第四章 Flink 窗口和水位线​

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 一、时间概念&#xff1a;事件时间和处理时间 在流式处理的过程中&#xff0c;数据…

详解微信小程序开发中的“数据绑定”和代码样例

简介 首先需要区分微信小程序的运行环境和框架系统。运行环境为小程序在手机当中运行的时候&#xff0c;微信客户端所能提供的环境支持&#xff0c;也就是在这种环境下如何进行数据渲染工作&#xff1b;框架系统则是微信小程序在进行开发的过程中&#xff0c;如何通过代码实现…

数字逻辑理论——组合电路

利用数据选择器设计组合逻辑电路 m&#xff1a;组合电路输入变量个数 n&#xff1a;数据选择器的控制端个数 &#xff08;1&#xff09;mn 利用8选1数据选择器设计函数&#xff1a;FAB’A’CBC’ 待设计卡诺图&#xff1a; F∑(1,2,3,4,5,6) &#xff08;2&#xff09;m&g…

【每日一题】【LeetCode】【第十九天】【Python】汇总区间

解决之路 题目描述 测试案例&#xff08;部分&#xff09; 第一次 没有想到什么更快的方法&#xff0c;先用两个循环来写出来思路。 class Solution(object):def summaryRanges(self, nums):res []index 0n len(nums)while index < n:if index n - 1:res.append(str…