如何解决回调地狱,看完这篇你就知道了

235 阅读3分钟

1.回调地狱什么时候会出现?

在做开发的时候,我们想依次读取依次读取文件 1.txt , 2.txt , 3.txt 这三个文件内容,是不可以直接按照顺序一个一个读取的,因为异步操作是无序的,我们发送的请求会按照无序返回给我们,打个比方:ajax就是我们最常见的发送请求后,无序执行返回数据的啦!!! 常见的异步操作有哪些呢?

1.png

Snipaste_2022-06-16_19-45-28.png 以上图片为回调地狱!!!!

比如依次读取文件 1.txt , 2.txt , 3.txt :

// 依次读取 文件  1.txt , 2.txt , 3.txt 这三个文件内容
const fs = require('fs');

//(1)能直接按照顺序写吗?  : 不能,因为异步操作 是无序的
fs.readFile("./data/1.txt", 'utf-8', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data);
    };
});

fs.readFile("./data/2.txt", 'utf-8', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data);
    };
});

fs.readFile("./data/3.txt", 'utf-8', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data);
    };
});
会随机出现顺序

//(2)解决方案 : 在回调函数中嵌套执行
//弊端 : 形成回调地狱(异步回调 层层嵌套,非常麻烦且不便于维护)
//读取文件1
fs.readFile("./data/1.txt", 'utf-8', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data);
        //1读取成功之后开始读取2
        fs.readFile("./data/2.txt", 'utf-8', (err, data) => {
            if(err){
                console.log(err);
            }else{
                console.log(data);
                //2读取成功之后开始读取3
                fs.readFile("./data/3.txt", 'utf-8', (err, data) => {
                    if(err){
                        console.log(err);
                    }else{
                        console.log(data);
                    }
                });
            }
        });
    }
});
 

这时候我们可以依次读取文件,但是我们的代码已经形成了回调地狱,异步回调,层层嵌套的关系,就像是一个千层饼.但是如果要读取多个文件,我们这样写,代码维护非常麻烦且不便于维护了.那么我们遇到这种情况并且想要他们按照我们的顺序乖乖执行时,我们可以怎么解决呢?

解决方法(1)

ES6中,我们采取Promise去解决回调地狱的问题

1.什么是Promise呢?

Promise 是一个构造函数, 用于创建Promise对象 Promise对象:咱们可以理解为一个处理异步操作的容器 真正异步的是它的两个回调resolve()和reject()

2.使用步骤

  • 1.实例化Promise对象

    • 作用: 将异步操作代码 放入 Promise中

      • resolve:异步操作 成功状态
      • reject : 异步操作 失败状态

new Promise((resolve,reject)=>{ 你的异步操作 })`

  • 2.调用then()方法处理异步操作结果

    promise对象.then((data)=>{ 处理成功数据 },(err)=>{ 处理失败信息 });

2.png

const fs = require("fs");

/* 
promise实例对象的catch方法 : 用于捕获异步操作的错误信息
*/


//1.封装一个函数 :  根据文件名生成  文件读取的promise
function getPromise(fileName) {
    let p = new Promise((resolve, reject) => {
        //读文件
        fs.readFile(`./data/${fileName}.txt`, 'utf-8', (err, data) => {
            if (err == null) {
                //成功
                resolve(data);
            } else {
                //失败
                reject(err);
            }
        });
    });
    return p;
};

//2.解决需求: 要先读1, 读完1后读2, 读完2后读3.

//开始读取a
getPromise('1').then((data)=>{
    console.log(data);
    //继续读取2
    return getPromise('2');
}).then((data)=>{
    console.log(data);
    //继续读取3
    return getPromise('3');
}).then((data)=>{
    console.log(data);
}).catch((err)=>{
    //以上三个异步操作,只要有任何一个出错,都会执行err
    console.log(err);
});

解决方法(2)

ES7中,我们采取异步函数async与await去解决回调地狱的问题

1.什么是异步函数async呢?

异步函数async相当于是promise语法的 “高级写法” ES2017中引入的更为高级的异步处理机制,async函数,可以让异步的处理变的更加便捷 出自:阮一峰-async函数

2.使用步骤

async语法如下

  • (1)函数前面使用async修饰

  • (2) 函数内部,promise操作使用await修饰 也就是说他两要在一起搭配使用

    • await 后面是promise对象, 左侧的返回值就是这个promise对象的then方法中的结果
    • await必须要写在async修饰的函数中,不能单独使用,否则程序会报错
const fs = require("fs");

/* 
promise实例对象的catch方法 : 用于捕获异步操作的错误信息
*/


//1.封装一个函数 :  根据文件名生成  文件读取的promise
function getPromise(fileName) {
    let p = new Promise((resolve, reject) => {
        //读文件
        fs.readFile(`./data/${fileName}.txt`, 'utf-8', (err, data) => {
            if (err == null) {
                //成功
                resolve(data);
            } else {
                //失败
                reject(err);
            }
        });
    });
    return p;
};

//2.解决需求: 要先读1, 读完1后读2, 2后读3.

// async和await异步函数 :  这两个关键字只能用于函数, 所以用的时候一定要放在函数里面用

/* 
async关键字:  修饰函数。  表示这个函数内部有异步操作。 
await关键字:  等待异步执行完毕。
    (1)await只能用于被async修饰的函数中。  
        只有当await后面的异步操作执行完毕后,才会继续执行后面代码
    (2)await 后面 只能是promise对象
*/

const readFile = async () => {
    
    let data1 = await getPromise('1')
    console.log(data1)

    let data2 = await getPromise('2')
    console.log(data2)

    //async异步函数的错误信息要用try-catch来捕捉
    try {
        let data3 = await getPromise('3')
        console.log(data3)
    } catch (err) {
        console.log(err)

    }
}

readFile()

宝,你学废了me? 一个爱敲代码的小姐姐