回调地狱与 Promise

在使用 Ajax 的过程中,经常会遇到这种情况:我们需要在一个 Ajax 里面嵌套另一个 Ajax 调用,有时候甚至需要嵌套好几层 Ajax 调用,于是就形成了所谓的“回调地狱”:

这种代码最大的问题是可读性非常差,时间长了之后根本无法维护。

Promise 的出现主要就是为了解决这个问题,在 Promise 的场景下,我们可以这样写代码:

new Promise(function(resolve,reject){//异步操作之后用resolve返回data
})
.then(function(data){//依赖于Promise的第一个异步操作
})
.then(function(data){//依赖于Promise的第二个异步操作
})
.then(function(data){//依赖于Promise的第三个异步操作
})
.catch(function(reason){//处理异常
});

很明显,这样的代码可读性就强太多了,而且未来维护起来也很方便。

当然,Promise 的作用不止于此,如果你想更细致地研究 Promise,请看 MDN 上的这篇资料。

RxJS 与 Promise 的共同点

RxJS 与 Promise 具有相似的地方,请看以下两个代码片段:

let promise = new Promise(resolve => {setTimeout(() => {resolve('---promise timeout---');}, 2000);
});
promise.then(value => console.log(value));
let stream1$ = new Observable(observer => {let timeout = setTimeout(() => {observer.next('observable timeout');}, 2000);return () => {clearTimeout(timeout);}
});
let disposable = stream1$.subscribe(value => console.log(value));

可以看到,RxJS 和 Promise 的基本用法非常类似,除了一些关键词不同。Promise 里面用的是 then() 和 resolve(),而 RxJS 里面用的是 next() 和 subscribe()。

RxJS 与 Promise 的3大重要不同点

任何一种技术或者框架,一定要有自己的特色,如果跟别人完全一样,解决的问题也和别人一样,那存在的意义和价值就会遭到质疑。

所以,RxJS 一定有和 Promise 不一样的地方,最重要的不同点有3个,请看下图:

依次给3块代码来示范一下:

let promise = new Promise(resolve => {setTimeout(() => {resolve('---promise timeout---');}, 2000);
});
promise.then(value => console.log(value));
let stream1$ = new Observable(observer => {let timeout = setTimeout(() => {observer.next('observable timeout');}, 2000);return () => {clearTimeout(timeout);}
});
let disposable = stream1$.subscribe(value => console.log(value));
setTimeout(() => {disposable.unsubscribe();
}, 1000);

从以上代码可以看到,Promise 的创建之后,动作是无法撤回的。Observable 不一样,动作可以通过 unsbscribe() 方法中途撤回,而且 Observable 在内部做了智能的处理,如果某个主题的订阅者为0,RxJS 将不会触发动作。

let stream2$ = new Observable(observer => {let count = 0;let interval = setInterval(() => {observer.next(count++);}, 1000);return () => {clearInterval(interval);}
});
stream2$.subscribe(value => console.log("Observable>"+value));

以上代码里面我们用 setInterval 每隔一秒钟触发一个新的值,源源不断,就像流水一样。

这一点 Promise 是做不到的,对于 Promise 来说,最终结果要么 resole(兑现)、要么 reject(拒绝),而且都只能触发一次。如果在同一个 Promise 对象上多次调用 resolve 方法,则会抛异常。而 Observable 不一样,它可以不断地触发下一个值,就像 next() 这个方法的名字所暗示的那样。

let stream2$ = new Observable(observer => {let count = 0;let interval = setInterval(() => {observer.next(count++);}, 1000);return () => {clearInterval(interval);}
});
stream2$.filter(val=>val%2==0).subscribe(value => console.log("filter>"+value));
stream2$.map(value => value * value).subscribe(value => console.log("map>"+value));

在上述代码里面,我们用到了两个工具函数:filter 和 map。

  • filter 的作用就如它的名字所示,可以对结果进行过滤,在以上代码里面,我们只对偶数值有兴趣,所以给 filter 传递了一个箭头函数,当这个函数的返回值为 true 的时候,结果就会留下来,其它值都会被过滤掉。
  • map 的作用是用来对集合进行遍历,比如例子里面的代码,我们把 Observable 返回的每个值都做了一次平方,然后再传递给监听函数。

类似这样的工具方法在 Observable 里面叫做 operator(操作符),所以有人说 Observable 就相当于异步领域的 Underscore 或者 lodash,这样的比喻是非常贴切的。这也是 Observable 比较强的地方,Promise 里面就没有提供这些工具函数。

Observable 里面提供了数百个这样的“操作符”,完整的列表和API文档请参考这里。

我也看到有一些朋友在抱怨,说 RxJS 太过复杂,操作符的数量又特别多,不知道在什么场景下面应该用什么操作符。

实际上这种担心是多余的,因为在 RxJS 里面最常用的操作符不超过10个,不常用的操作符都可以在使用的时候再去查阅文档。

RxJS 和你自己开发的系统一样,常用的功能只有其中的20%,而剩余80%的功能可能永远不会被用到。所以,RxJS 并不像很多人说的那么玄乎,你一定能学会,我相信你。

RxJS 在 Angular 的典型应用场景1:http 服务

this.http
.get(url,{search:params})
.map((res:Response) => {let result=res.json();console.log(result);return result;
})
.catch((error:any) => Observable.throw(error || 'Server error'));

在新版本的 Angular 里面,http 服务的返回值都是 Observable 类型的对象,所以我们可以 subscribe(订阅)这个对象。当然,Observable 所提供的各种“操作符”都可以用在这个对象上面,比如上面这个例子就用到了 map 操作符。

RxJS 在 Angular 的典型应用场景2:事件处理

this.searchTextStream
.debounceTime(500)
.distinctUntilChanged()
.subscribe(searchText => {console.log(this.searchText);this.loadData(this.searchText)
});

这个例子里面最有意思的部分是 debounceTime 方法和 distinctUntilChanged 方法,这是一种“去抖动”效果。“去抖动”这个场景非常能体现 Observable 的优势所在,有一些朋友可能没遇到过这种场景,我来解释一下,以防万一。

在搜索引擎里面,我们经常会看到这样的效果:

这种东西叫做“动态搜索建议”,在用户敲击键盘的过程中,浏览器已经向后台发起了请求,返回了一些结果,目的是给用户提供一些建议。

效果看起来很简单,但是如果没有这个 debounceTime 工具函数,我们自己实现起来是非常麻烦的。这里的难点在于:用户敲击键盘的过程是源源不断的,我们并不知道用户什么时候才算输入完成。所以,如果让你自己来从零开始实现这种效果,你将会不得不使用定时器,不停地注册、取消,自己实现延时,还要对各种按键码做处理。

在 Observable 里面,处理这种情况非常简单,只要一个简单的 debounceTime 加 distinctUntilChanged 调用就可以了。

Promise 与 RXJS的区别相关推荐

  1. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )

    Promise 是 ES 6 Async/Await 是 ES 7 Rxjs 是一个 js 库 在使用 angular 时,你会经常看见这 3 个东西. 它们都和异步编程有关,有些情况下你会觉得用它们 ...

  2. promise 和 async await区别

     什么是Async/Await? async/await是写异步代码的新方式,以前的方法有回调函数和Promise. async/await是基于Promise实现的,它不能用于普通的回调函数. as ...

  3. Promise.all()、Promise.allSettled()、Promise.any()、Promise.race()用法与区别

    概述 Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值 一个 Promise 必然处于以下几种状态之一: 待定(pending): 初始状态,既没有被兑现,也没有被拒绝. 已兑 ...

  4. promise 和 Observable 的区别

    StackOverflow 上的讨论:What is the difference between Promises and Observables? 得赞最高的一个回答:1777 赞 当异步操作完成 ...

  5. 2019年12月前端面经及总结(西安,杭州)

    2019年12月前端面经及总结(西安,杭州) 我的github主页:https://github.com/dashnowords 我的新书上架啦,3天即登京东计算机编程语言类排行榜Top1!!!精选3 ...

  6. C++ 中 async、packaged_task、promise 区别及使用

    Introduction 编程难,多线程编程更难 – 鲁迅 多线程编程,如此令人着迷.令人痛恨的字眼.人类为了追求更好的效率.更快的速度,非常残忍的发明了多线程编程,这不仅让写代码的难度陡增,同时也加 ...

  7. 浅谈Generator和Promise原理及实现

    Generator 熟悉ES6语法的同学们肯定对Generator(生成器)函数不陌生,这是一个化异步为同步的利器. 栗子: function* abc() {let count = 0;while( ...

  8. promise用法_图解 Promise 实现原理(四):Promise 静态方法实现

    作者:Morrain 转发链接:https://mp.weixin.qq.com/s/Lp_5BXdpm7G29Z7zT_S-bQ 前言 Promise 是异步编程的一种解决方案,它由社区最早提出和实 ...

  9. promise链式调用_这一次,彻底弄懂 Promise

    Promise 必须为以下三种状态之一:等待态(Pending).执行态(Fulfilled)和拒绝态(Rejected).一旦Promise 被 resolve 或 reject,不能再迁移至其他任 ...

最新文章

  1. 病毒周报(091102至091108)
  2. ICML 2020论文贡献榜排名出炉:Google单挑斯坦福、MIT、伯克利;清华进TOP 20
  3. Android Jetpack组件之Navigation使用-源码
  4. 利用开源中国提供的代码仓库提高github下载速度
  5. 使用 Spring Cloud 实现微服务系统
  6. HTML 事件响应函数,HTML5: 事件处理函数的this指向问题
  7. 你知道url中的特殊符号含义么
  8. 汉字的Unicode表位置
  9. Cadence Allegro剪断走线图文教程及视频演示
  10. 什么是函数指针 ? 什么是指针函数? int (*P)( ) 和int *p()有什么区别
  11. 彻底理解样本方差为何除以n-1
  12. Ubuntu版本及对应的代号(4.10-22.04) 共18年整理
  13. 数据文化 | Uber的数据治理
  14. MYSQL基本操作(增删改查)
  15. 统一自定义idea和eclipse代码格式化和注释格式化总结
  16. 2021csp-j2 题解
  17. 穷人python入门教程视频_穷的解释|穷的意思|汉典“穷”字的基本解释
  18. 中 华 百 家 姓 一 览
  19. icinga用NSCA监控远程Linux服务器
  20. python中math的ln_Python math库 ln(x)运算的实现及原理

热门文章

  1. 高斯投影正反算C语言程序代码,高斯投影正反算c代码
  2. 运动模糊图像复原算法实现及应用
  3. 前端基础----html初识、常用标签
  4. Distribute Strategy--翻译学习
  5. 蓝桥杯——罗马数字转换器
  6. 电脑连接手机热点时,电脑能够搜到但是却连接不上的问题
  7. imputation-文献:False signals induced by single-cell imputation(scRNA-seq插补引入的假阳性问题)
  8. ARM开发工具综述转
  9. IE浏览器高通网站打不开dump分析选择目录总结
  10. 应对Apple Music断续费后歌单被删除的一个解决方案