Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >什么是回调地狱?如何解决回调地狱问题_地狱回调

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

作者头像
全栈程序员站长
发布于 2022-11-15 06:08:32
发布于 2022-11-15 06:08:32
3.7K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

一、什么是回调地狱呢?

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

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

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

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

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	使用fs.readFile(‘./demo.txt’,(err,result) =>{});
	上面这个就是一个异步API
	是使用系统模块fs去查看文件

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	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个文件就创建好了,进入码代码的环节啦
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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个呢

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
})
})
})
})
})
})
})
})
})
})
});

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	Promise的出现就是解决Node.js异步编程中回调地狱的问题
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
基础语法
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. 开始代码的编写
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//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、改进的方法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 优化(异步函数)

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const fn = async() =>{ 
};
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
async function fn(){ 
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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、总结
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//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.cn/234800.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年11月1日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Node.js异步编程(下)
如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题要怎么解决呢?
Qwe7
2022/04/23
8010
JavaScript——ES6模块化与异步编程高级用法
大家都遵守同样的模块化规范写代码,降低了沟通程表,极大方便了各个模块之间的相互调用,利人利己。
岳泽以
2022/10/26
7850
JavaScript——ES6模块化与异步编程高级用法
Promise用法详解(一)
注意:上面new出来promise,只代表形式上的一个异步操作。就是说,我们只知道他是一个 异步操作,但做什么具体异步事情目前还不清楚。
全栈程序员站长
2022/07/04
4050
Promise用法详解(一)
async关键字
在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
Qwe7
2022/04/23
2860
ES6模块化与异步编程
::: tip ES6 模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学习成本,开发者不需再额外学习 AMD、CMD 或 CommonJS 等模块化规范。
小城故事
2023/04/03
6090
ES6模块化与异步编程
【ES6+】010-ES8新特性:async和await、对象方法扩展
訾博ZiBo
2025/01/06
730
【ES6+】010-ES8新特性:async和await、对象方法扩展
nodejs(三)
必须在 package.json 的根节点中添加 "type": "module" 节点
且陶陶
2023/04/12
4600
nodejs(三)
ES6新特性
由于ES6在一些低版本的浏览器上无法运行,需转成ES5之前的版本兼容,以下有几种方案可以自动转换
jinghong
2020/05/09
1.1K0
ES6新特性
Promise解决回调嵌套问题及终极解决方案async 和 await
目的: promise是书写异步代码的另一种方式, 解决回调函数嵌套的问题 1.如何创建一个 promise 对象
青梅煮码
2023/03/02
2.4K0
异步发展流程-手摸手带你实现一个Promise
首先介绍一下高阶函数,即一个函数的参数是函数或者函数返回值为函数,此函数称做高阶函数。
Careteen
2022/02/14
9870
【JS】236-JS 异步编程六种方案(原创)
我们知道Javascript语言的执行环境是"单线程"。也就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。
pingan8787
2019/07/25
1K0
【JS】236-JS 异步编程六种方案(原创)
从零开始写一个符合Promises/A+规范的promise
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。本篇不注重讲解promise的用法,关于用法,可以看阮一峰老师的ECMAScript 6系列里面的Promise部分:
Nealyang
2019/09/29
1.5K0
从零开始写一个符合Promises/A+规范的promise
【ES6+】006-ES6新特性:Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果;
訾博ZiBo
2025/01/06
1030
【ES6+】006-ES6新特性:Promise
Node.js异步编程
1. 同步API,异步API //路径拼接 const public = path.join(_ dirname, 'public') ; //通过返回值拿到 //请求地址解析 const url0bj = url. parse (req. ur1) ; //通过返回值拿到 //读取文件 fs. readFile(' ./demo.txt', 'utf8', (err, result) => { console .1og (result) ; }) ; //通过函数方式拿到 同步API:只有当前
清出于兰
2020/10/29
2K0
Node.js异步编程
记两道关于事件循环的题
这里的关键其实是搞清楚 await async2() 做了什么事情。我以为在 async1 内部,async2 被调用之后,就会继续往后执行,因此是先打印 async1 end ,再回到主栈打印 start。然而 async2 里面包含了一个异步操作,在异步操作得到结果之前,其实是会跳出当前 async1 函数的执行栈,优先去执行同步任务的,所以这里其实会先执行 start,再去执行 async1 end。具体地说:
Chor
2020/05/18
4230
ES6-11
Rest 参数与 spread 扩展运算符在es6中已经引入,但仅限于数组,es9中为对象提供了像数组一样的 rest 参数和扩展运算符
4O4
2022/04/25
2800
解释Promise的基本用法及状态
在 JavaScript 中,Promise 是一种用于处理异步操作的对象。它代表一个可能在未来某个时间点完成的操作,并为这样的操作提供了更清晰的处理方式。Promise 的引入使得处理异步代码变得更加直观,避免了回调地狱的问题。本文将详细介绍 Promise 的基本用法、状态及其使用场景。
王小婷
2025/05/25
1290
JavaScript 异步编程指南 — Give me a Promise
随着 ES6 标准的出现,给我们带来了一个新的异步解决方案 Promise。目前绝大多数 JavaScript 新增的异步 API 无论是在浏览器端还是 Node.js 服务端都是基于 Promise 构建的,以前基于 Callback 形式的也有解决方案将其转为 Promise。
一只图雀
2021/06/17
1.3K0
JavaScript 异步编程指南 — Give me a Promise
JS高阶(一)Promise
作用:存储对象失败或成功的结果; 修改:resolve、reject 函数可以修改 result 的值;
DioxideCN
2022/08/05
2.5K0
将CallBack改写成Promise
CallBack回调函数是js的特色之一, 但CallBack回调方法, 非常容易造成回调地狱(callback hell), 回调地狱不仅形象丑陋,而且代码难以维护
zhaoolee
2019/07/12
2.3K0
将CallBack改写成Promise
相关推荐
Node.js异步编程(下)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验