什么是回调地狱?如何解决回调地狱问题_地狱回调

什么是回调地狱?如何解决回调地狱问题_地狱回调什么是回调地狱?该如何解决回调地狱?

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

一、什么是回调地狱呢?

	地狱这个词不陌生吧!对,没错就是那个十八层地狱的地狱,一层一层的地狱。

Jetbrains全家桶1年46,售后保障稳定

1、同步API,异步API的区别

这个问题呢,需要从Node.js的API说起,这里就会有人问了?博主你不是说回调地狱的问题吗,怎么说到API了,别急,看博主一步一步的解释给你听:

同步API 是从上到下依次执行,前面的代码会阻塞后面的代码执行
请看下面这个代码


这里我写了一个for询还1000次,在循环里面打印,在循环体后面是另外的一个打印结果
结果是什么呢?
这个需要你自己去敲一下代码才能更好的了解喔!

for(var i=0; i<1000; i++){ 
   
	console.log(i);
}
console.log('循环体后面的代码')

异步API不会等待API执行完后在向下执行代码
看下下面这个代码,会是如何执行呢?

console.log('代码开始执行')
//异步操作 setTimout
setTimout(() =>{ 
    console.log('5秒后执行代码') },5000);//5000就是5秒
setTimout(() =>{ 
    console.log('0秒后执行代码')},0);
console.loh('代码结束执行');

这里的执行顺序是:
代码开始执行
代码结束执行
0秒后执行代码
5秒后执行代码

逻辑梳理:先执行同步的API,在去执行异步的API
      同步API有两个  分别是两个console.log
      异步API也有两个 分别是setTimout
      异步API里面的定时器会先执行0  在执行5

2、Node.js中的异步API

	使用fs.readFile(‘./demo.txt’,(err,result) =>{});
	上面这个就是一个异步API
	是使用系统模块fs去查看文件

如果异步API后面的代码执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题怎么解决呢?

	fs.readFile(‘./demo.txt’,(err,result) =>{});
	console.log('文件打印结果')

3、写一个使用异步API,造成的回调地狱案例

案例需求:依次读取A文件,B文件,C文件

  1. 首先需要创建一个js的文件
  2. 然后分别创建1.txt 2.txt 3.txt
  3. 在每个文本里面写分别写上1 2 3
  4. 这样我们3个文件就创建好了,进入码代码的环节啦
const fs = require('fs')

fs.readFile('./1.txt','utf8',(err,result1) =>{ 
   
    console.log(result1);
    fs.readFile('./2.txt','utf8',(err,result2) =>{ 
   
        console.log(result2);

        fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
            console.log(result3);

        })
    })
});

执行这个js文件,执行结果是正确的,是不是没毛病!
但是这我们只写了3个,要是我们写18个呢

const fs = require('fs')

fs.readFile('./1.txt','utf8',(err,result1) =>{ 
   
    console.log(result1);
    fs.readFile('./2.txt','utf8',(err,result2) =>{ 
   
        console.log(result2);

        fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
            console.log(result3);
            fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                console.log(result3);
                fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                    console.log(result3);
                    fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                        console.log(result3);
                        fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                            console.log(result3);
                            fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                                console.log(result3);
                                fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                                    console.log(result3);
                                    fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                                        console.log(result3);
                                        fs.readFile('./3.txt','utf8',(err,result3) =>{ 
   
                                            console.log(result3);
                                
                                        })
                                    })
                                })
                            })
                        })
                    })
                })
            })
        })
    })
});

这样你能理解了吗?这样一层回调嵌套一层回调,是不是有点像地狱的样子!这样的代码也不易去维护。

二、怎么解决回调地狱呢?

	Promise的出现就是解决Node.js异步编程中回调地狱的问题
基础语法
let promise = new Promise((resolve,reject) =>{ 
   
	setTimout(() =>{ 
   
	if(true){ 
   
	//resolve将异步API的执行结果传递出去
	    resolve({ 
   name:"张三"})
	}else{ 
   
		//reject 也是一个函数,当判断失败的时候,将结果传递出去
  		reject('失败了')
  }	
},2000);
})
//成功了
promise.then(result => console.log(result));//{name:‘张三’}
		.catch(error => console.log(error));//失败了

1、使用Promise来完成我们之前做的案例

  1. 创建一个js文件
  2. 文件可以就用之前的文件
  3. 开始代码的编写
//1、引入系统模块fS
const fs = require('fs');

//2、创建一个promise对象
let promise = new Promise((resolve,reject) =>{ 
   

    fs.readFile('./1.txt','utf8',(err,result) =>{ 
   
        if(err !=null){ 
   
            reject(err);
        }else{ 
   
            resolve(result);
        }
    });
});
//文件成功的信息
promise.then((result) =>{ 
   
    console.log(result);
})
//文件失败的信息
.catch((err) =>{ 
   
    console.log(err);
})

2、改进的方法

const fs = require('fs')
function p1(){ 
   
    return new Promise((resolve,reject) =>{ 
   
        fs.readFile('./1.txt','utf8',(err,result) =>{ 
   
            resolve(result);
        })
    })
}
function p2(){ 
   
     return new Promise((resolve,reject) =>{ 
   
        fs.readFile('./2.txt','utf8',(err,result) =>{ 
   
            resolve(result);
        })
    })
}
function p3(){ 
   
    return new Promise((resolve,reject) =>{ 
   
        fs.readFile('./3.txt','utf8',(err,result) =>{ 
   
            resolve(result);
        })
    })
}
//依次执行1、2、3
p1().then((r1) =>{ 
   
    console.log(r1);
    //return p2
    return p2();
})
.then((r2) =>{ 
   
    console.log(r2);
    //return p3()
    return p3();
})
.then((r3) =>{ 
   
    console.log(r3);
})

读到这里,你知道什么是回调地狱了吗?并且如何解决它了吗?
切记!看代码或者看文章的记忆并不深刻哟,要自己去敲代码,这个在面试中也是经常会出现哟!码字不易,希望能一键三连

2021.3月31日更新

3、ES7 优化(异步函数)

异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了

const fn = async() =>{ 
   };
async function fn(){ 
   }

之前的案例,优化后的代码如下

const fs = require('fs');
const  promisify  = require("util").promisify;
const readFile = promisify(fs.readFile);

async function run() { 
   
 let  r1 = await readFile('./1.txt','utf8')
  let r2 =  await readFile('./2.txt','utf8')
   let r3 = await readFile('./3.txt','utf8')
    console.log(r1);
    console.log(r2);
    console.log(r3);
}
run();

4、总结

//1.在普通函数定义的前面加上async关键字 普通函数就变成的异步函数
//2.异步函数默认的返回值是promise对象
//3.在异步函数内部使用throw关键字进行错误的抛出

//await关键字
//1.它只能出现在异步函数中
//2.await promise 它可以暂停异步函数的执行 等待promise对象返回结果后在向下执行

async function p1() { 
   
    return '1';
}
async function p2() { 
   
    return '2';
}
async function p3() { 
   
    return '3';
}
async function run() { 
   
      let r1 = await p1()
      let r2 = await p2()
      let r3 = await p3()
    console.log(r1);
    console.log(r2);
    console.log(r3);

}
run();
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/234800.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ArcGIS与地理加权回归GWR【一】「建议收藏」

    ArcGIS与地理加权回归GWR【一】「建议收藏」公众号原文ArcGIS与地理加权回归GWR【一】https://mp.weixin.qq.com/s/fMPYxO3G7ff2192ZQICN-A开个新坑啊,写一写关于地理加权回归基础的东西(深了我也不会啊),希望也能用通俗的语言来记录一下我以前学习空间统计过程中的理解。1.传统线性回归不管你有没有系统学习过,对于线性回归,相信多少都有那么点了解。回归分析实质上就是研究一个或多个自变量X对一个因变量Y的影响关系情况,如研究各地房价影响因素。X1-Xn是n个自变量,β0-βn是未

    2022年10月7日
    0
  • java random函数原理_详解JAVA中Random()函数的用法

    java random函数原理_详解JAVA中Random()函数的用法有时候,我们会用到随机数。java中自带的Random()函数让我们可以很方便的产生随机数。本文介绍它的一些用法。随机数是专门的随机试验的结果。在统计学的不同技术中需要使用随机数,比如在从统计总体中抽取有代表性的样本的时候,或者在将实验动物分配到不同的试验组的过程中,或者在进行蒙特卡罗模拟法计算的时候等等。产生随机数有多种不同的方法。这些方法被称为随机数发生器。随机数最重要的特性是:它所产生的后面…

    2022年5月10日
    42
  • linux命令行怎么结束进程,linux结束进程命令「建议收藏」

    linux命令行怎么结束进程,linux结束进程命令「建议收藏」linux下进程的开启与结束都可以通过命令来控制,下面由学习啦小编为大家整理了linux下结束进程命令的相关知识,希望对大家有所帮助。linux结束进程命令1.killkill[信号代码]根据PID向进程发送信号,常用来结束进程,默认信号为-9信号代码,可取值如下:-l[信号数字]显示、翻译信号代码-9,-KILL发送kill信号退出-6,-ABRT发送abort信号…

    2025年6月22日
    0
  • awstats分析nginx日志「建议收藏」

    awstats分析nginx日志「建议收藏」看了awstats介绍后,感觉是个好东西,等装好来用的时候,不像那么一回事。awstats说白了就是对nginx,apache产生的日志进行分析。awstats分析出来的数据不准,日志是按照一定的规则来生成的,把访问数据存入到文件中,但是数据存入的时候可能是不全的,awstats分析的时候就有误差。一,安装awstatsyuminstallawstats二,配置awstats1,nginx的日志格式查看复制打印?log_formataccess_www’$remote…

    2022年7月16日
    10
  • 网络分析最佳路径_局域网找不到网络路径

    网络分析最佳路径_局域网找不到网络路径网络分析——路径分析一、实验背景在远距离送货,物资派发、急救服务和邮递等服务中,经常需要在一次行程中同时访问多个站点(收货方、邮件主人、物资储备站等),如何寻找到一个最短和最经济的路径,保证访问到所有站点,同时最快最省地完成一次行程,这是很多机构遇到的问题。为解决这类问题,我们需要学习基于ArcGIS网络分析功解决实际路径问题,掌握网络分析基本技能。二、实验内容根据不同的要求,获得到达指…

    2022年8月24日
    6
  • Visual Studio 连接SQL Server数据库[通俗易懂]

    Visual Studio 连接SQL Server数据库[通俗易懂]VisualStudio连接SQLServer数据库在visualStudio开发环境中,从菜单中选择“工具”->“链接到数据库”命令,然后弹出图(1)所示窗口,点击更改按钮,选择你所使用的数据源类型,如下图(2)所示,点击确定。图(1)更改数据源类型图(2)选择数据源类型此时可以点击“浏览”按钮添加数据库文件,如下图(3)所示…

    2022年7月24日
    23

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号