Promise一招解决回调地狱

news/2024/7/10 0:36:35 标签: vue, es6, js, promise

问题

首先,什么是回调地狱:

  • 层嵌套的问题。
  • 每种任务的处理结果存在两种可能性(成功或失败),那么需要在每种任务执行结束后分别处理这两种可能性。

当一个接口需要依赖另一个接口的请求数据时,通常有两种解决方式

  • 将请求数据的接口设为同步,之后调另一个接口
  • 在请求数据接口的成功回调里调另一个接口

这两种问题在回调函数时代尤为突出。Promise 的诞生就是为了解决这两个问题。
典型的高阶函数,将回调函数作为函数参数传给了readFile。但久而久之,就会发现,这种传入回调的方式也存在大坑, 比如下面这样:

fs.readFile('1.json', (err, data) => {
    fs.readFile('2.json', (err, data) => {
        fs.readFile('3.json', (err, data) => {
            fs.readFile('4.json', (err, data) => {

            });
        });
    });
});

回调当中嵌套回调,也称回调地狱。这种代码的可读性和可维护性都是非常差的,因为嵌套的层级太多。而且还有一个严重的问题,就是每次任务可能会失败,需要在回调里面对每个任务的失败情况进行处理,增加了代码的混乱程度。

解决方案

Promise 利用了三大技术手段来解决回调地狱:

  • 回调函数延迟绑定。
  • 返回值穿透。
  • 错误冒泡。

首先来举个例子:

let readFilePromise = (filename) => {
    fs.readFile(filename, (err, data) => {
        if(err) {
            reject(err);
        }else {
            resolve(data);
        }
    })
}
readFilePromise('1.json').then(data => {
    return readFilePromise('2.json')
});

看到没有,回调函数不是直接声明的,而是在通过后面的 then 方法传入的,即延迟传入。这就是回调函数延迟绑定。

然后我们做以下微调:

let x = readFilePromise('1.json').then(data => {
    return readFilePromise('2.json')//这是返回的Promise
});
x.then(/* 内部逻辑省略 */)

我们会根据 then 中回调函数的传入值创建不同类型的Promise, 然后把返回的 Promise 穿透到外层, 以供后续的调用。这里的 x 指的就是内部返回的 Promise,然后在 x 后面可以依次完成链式调用。

这便是返回值穿透的效果。

这两种技术一起作用便可以将深层的嵌套回调写成下面的形式:

readFilePromise('1.json').then(data => {
    return readFilePromise('2.json');
}).then(data => {
    return readFilePromise('3.json');
}).then(data => {
    return readFilePromise('4.json');
});

这样就显得清爽了许多,更重要的是,它更符合人的线性思维模式,开发体验也更好。

两种技术结合产生了链式调用的效果。

这解决的是多层嵌套的问题,那另一个问题,即每次任务执行结束后分别处理成功和失败的情况怎么解决的呢?

Promise采用了错误冒泡的方式。其实很简单理解,我们来看看效果:

readFilePromise('1.json').then(data => {
    return readFilePromise('2.json');
}).then(data => {
    return readFilePromise('3.json');
}).then(data => {
    return readFilePromise('4.json');
}).catch(err => {
  // xxx
})

这样前面产生的错误会一直向后传递,被catch接收到,就不用频繁地检查错误了。

觉得写得不错的话,请用你们发财的小手点个赞叭!


http://www.niftyadmin.cn/n/658236.html

相关文章

js判断数字的合法性

//验证是否为数字function isNumber(oNum){if(!oNum) return false;var strP/^/d(/./d)?$/;if(!strP.test(oNum)) return false;try{if(parseFloat(oNum)!oNum) return false;}catch(ex){return false;}return true;}

线性基浅谈

线性基浅谈 一、线性基浅谈 在了解线性基之前,要简单理解什么是基。在线性代数中,基又称为基地,是刻画向量的工具。对于基底的元素我们称为基向量,向量空间的任意一个元素都可以唯一表示成为基向量的线性组合。同样,线…

所向披靡的async/await

使用规则 凡是在前面添加了async的函数在执行后都会自动返回一个Promise对象 注意重点: 返回结果为Promise。 async function test() { return 100; } console.log(test()) // Promise {<resolved>: 100} await必须在async函数里使用&#xff0c;不能单独使用async …

个税起征点升高----节省了多少?

个税起征点今年一月开始执行&#xff0c;大家大多可以节省不小的支出。可惜我的收入低&#xff0c;只节省了将近&#xff11;&#xff10;&#xff10;元。大家都节省多少&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;

fedora 国内源

wget http://mirrors.163.com/.help/fedora-163.repowget http://mirrors.163.com/.help/fedora-updates-163.repo 转载于:https://www.cnblogs.com/wangjq19920210/p/10694800.html

BZOJ2007: [Noi2010]海拔

BZOJ2007: [Noi2010]海拔 Description YT市是一个规划良好的城市&#xff0c;城市被东西向和南北向的主干道划分为nn个区域。简单起见&#xff0c;可以将YT市看作一个正方形&#xff0c;每一个区域也可看作一个正方形。从而&#xff0c;YT城市中包括(n1)(n1)个交叉路口和2n(n1)…

instanceOf 运算符原理

定义 instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置。 —— MDN 简单理解为&#xff1a;instanceof可以检测一个实例是否属于某种类型。 function Foo(){} const a new Foo()a instanceof Foo // true a instanceof Object /…

ElasticSearch文档及分布式文档存储

1、什么是文档&#xff1f; 文档由索引&#xff08;_index&#xff09;,类型&#xff08;_type&#xff09;,唯一标识(_id) 组成&#xff0c;我们为 _index(索引) 分配相关逻辑地址分片&#xff0c;该索引下的数据会根据索引以及类型计算哈希来分配数据存储的分片&#xff0c;文…