• 【Promise】黑马vue视频笔记(十一)


    1. 回调地狱

    多层回调函数的相互嵌套,就形成了回调地狱。

    setTimeout(() => {
    	console.log('延迟1秒输出')
    	setTimeout(() => {
    		console.log('延迟2秒输出')
    		setTimeout(() => {
    			console.log('延迟3秒输出')
    		}, 3000)
    	}, 2000)
    }, 1000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

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

    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. 基于回调函数按顺序读取文件内容

    import fs from "fs"
    fs.readFile('./file/1.txt', (err1, r1) => {
    	if (err1) return console.log(err1.message)
    	console.log(r1)
    	fs.readFile('./file/2.txt', (err2, r2) => {
    		if (err2) return console.log(err1.message)
    		console.log(r2)
    		fs.readFile('./file/3.txt', (err3, r3) => {
    			if (err3) return console.log(err1.message)
    			console.log(r3)
    		})
    	})
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

    npm i then-s
    
    • 1

    3.1 then-fs 的基本使用

    调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象

    因此可以调用 .then() 方法为每个 Promise 异步操作指定成功失败之后的回调函数。示例代码如下:

    import thenFs from 'then-fs'
    thenFs.readFile('./file/1.txt', 'utf8').then(r1 => { console.log(r1) }, err1 => { console.log(err1.message) })
    thenFs.readFile('./file/2.txt', 'utf8').then(r2 => { console.log(r2) }, err2 => { console.log(err2.message) })
    thenFs.readFile('./file/3.txt', 'utf8').then(r3 => { console.log(r3) }, err3 => { console.log(err3.message) })
    
    • 1
    • 2
    • 3
    • 4

    3.2 .then() 方法的特性

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

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

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

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

    3.4 通过 .catch 捕获错误

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

    import thenFs from 'then-fs';
    thenFs.readFile('./file/1.txt', 'utf8') // 1. 返回值是Promise的实例对象
    	.then((r1) => { // 2. 通过 .then为第一个Promise实例指定成功之后的回调函数
    		console.log(r1)
    		return thenFs.readFile('./file/2.txt','utf8') //3. 在第一个.then 中返回一个新的Promise实例对象
    	})
    	.then((r2) => { // 4. 继续调用 .then 为上一个 .then 的返回值(新的Promise实例)指定成功之后的回调函数
    		console.log(r2)
    		return thenFs.readFile('./file/3.txt','utf8') // 5. 在第二个 .then中返回一个新的Promise实例对象
    	})
    	.then((r3) => { // 6. 继续调用 .then 为上一个 .then的返回值(新的Promise)实例指定成功之后的回调函数
    		console.log(r3)
    	})
    	.catch(err => { // 捕获第一行发生的错误,并输出错误的信息
    		console.log(err.message);
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    import thenFs from 'then-fs';
    thenFs.readFile('./file/1.txt', 'utf8') // 1. 返回值是Promise的实例对象
    	
    	.catch(err => { // 捕获第一行发生的错误,并输出错误的信息
    		console.log(err.message);
    	})
    	.then((r1) => { // 2. 通过 .then为第一个Promise实例指定成功之后的回调函数
    		console.log(r1)
    		return thenFs.readFile('./file/2.txt','utf8') //3. 在第一个.then 中返回一个新的Promise实例对象
    	})
    	.then((r2) => { // 4. 继续调用 .then 为上一个 .then 的返回值(新的Promise实例)指定成功之后的回调函数
    		console.log(r2)
    		return thenFs.readFile('./file/3.txt','utf8') // 5. 在第二个 .then中返回一个新的Promise实例对象
    	})
    	.then((r3) => { // 6. 继续调用 .then 为上一个 .then的返回值(新的Promise)实例指定成功之后的回调函数
    		console.log(r3)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.5 Promise.all() 方法

    Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then
    操作(等待机制)。示例代码如下:

    import thenFs from 'then-fs'
    // 1. 定义一个数组,存放3个读文件的异步操作
    const promiseArr = [
    	thenFs.readFile('./file/1.txt','utf8'),
    	thenFs.readFile('./file/2.txt','utf8'),
    	thenFs.readFile('./file/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)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意:数组中 Promise 实例的顺序,
    就是最终结果的顺序!

    3.6 Promise.race() 方法

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

    import thenFs from 'then-fs'
    // 1. 定义一个数组,存放3个读文件的异步操作
    const promiseArr = [
    	thenFs.readFile('./file/1.txt','utf8'),
    	thenFs.readFile('./file/2.txt','utf8'),
    	thenFs.readFile('./file/3.txt','utf8')
    ]
    // 2. 将 Promise的数组,作为Promise.race()的参数
    Promise.race(promiseArr)
    	.then((result) => {	// 2.1 只要任何一个异步操作完成,就立即执行成功的回调函数(赛跑机制)
    		console.log(result);
    	})
    	.catch(err => { // 2.2 捕获Promise异步操作中的错误
    		console.log(err.message)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

    4.1 getFile 方法的基本定义

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

    注意:第 5 行代码中的 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) => {})
    	}) 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.3 获取 .then 的两个实参

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

    function getFile (fpath) {
    	// resolve 形参是:调用getFiles()方法时,通过.then指定的"成功的"回调函数
    	// reject 形参是:调用getFile()方法时,通过.then指定的"失败的"回调函数
    	return new Promise(function(resolve, reject) {
    	fs.readFile(fpath,'utf8',(err, dataStr) => {})
    	}) 
    }
    // getFile 方法的调用过程
    getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.4 调用 resolve 和 reject 回调函数

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

    function getFile (fpath) {
    	// resolve 形参是:调用getFiles()方法时,通过.then指定的"成功的"回调函数
    	// reject 形参是:调用getFile()方法时,通过.then指定的"失败的"回调函数
    	return new Promise(function(resolve, reject) {
    	fs.readFile(fpath,'utf8',(err, dataStr) => {
    			if(err) return reject(err) // 如果读取失败,则调用"失败的回调函数"
    			resolve(dataStr) // 如果读取成功,则调用"成功的回调函数"
    		})
    	}) 
    }
    // getFile 方法的调用过程
    getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    秒杀项目的总结及面试常见问题
    前端和后端在软件开发中的两个重要部分
    使用 Transformers 为多语种语音识别任务微调 Whisper 模型
    word行距怎么设置?专业排版,让文档更具吸引力!
    leetcode - 1293. Shortest Path in a Grid with Obstacles Elimination
    ifream标签中的子页面,操作父页面的元素
    《优化接口设计的思路》系列:第八篇—分页接口的设计和优化
    Unexpected WSL error错误处理备忘
    [bmim][Tf2N]离子液体(IL)负载UiO-66-PEI
    方案丨如何通过TSINGSEE青犀防溺水AI算法,实现水域的智能监管与风险预警?
  • 原文地址:https://blog.csdn.net/weixin_51233575/article/details/126004426