使用Promise链式调用解决多个异步回调的问题


Posted in Javascript onJanuary 15, 2017

介绍

所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

缺少场景支撑,对于新手而言,很难理解Promise的意义。

在《你不知道的JavaScript中》有个场景介绍得很形象:

我走到快餐店的柜台,点了一个芝士汉堡。我交给收银员1.47美元。通过下订单并付款,我已经发出了一个对某个值(就是那个汉堡)的请求。我已经启 动了一次交易。

但是,通常我不能马上就得到这个汉堡。收银员会交给我某个东西来代替汉堡:一张带有 订单号的收据。订单号就是一个 IOU(I owe you, 我欠你的)承诺(promise),保证了最 终我会得到我的汉堡。

所以我得好好保留我的收据和订单号。我知道这代表了我未来的汉堡,所以不需要担心, 只是现在我还是很饿!

在等待的过程中,我可以做点其他的事情,比如给朋友发个短信:“嗨,要来和我一起吃 午饭吗?我正要吃芝士汉堡。”

我已经在想着未来的芝士汉堡了, 尽管现在我还没有拿到手。 我的大脑之所以可以这么 做,是因为它已经把订单号当作芝士汉堡的占位符了。从本质上讲,这个占位符使得这个 值不再依赖时间。这是一个未来值。

终于, 我听到服务员在喊“订单 113” , 然后愉快地拿着收据走到柜台, 把收据交给收银 员,换来了我的芝士汉堡。

换句话说, 一旦我需要的值准备好了, 我就用我的承诺值(value-promise)换取这个值 本身。

但是,还可能有另一种结果。他们叫到了我的订单号,但当我过去拿芝士汉堡的时候,收 银员满是歉意地告诉我:“不好意思,芝士汉堡卖完了。”除了作为顾客对这种情况感到愤 怒之外,我们还可以看到未来值的一个重要特性:它可能成功,也可能失败。

每次点芝士汉堡,我都知道最终要么得到一个芝士汉堡,要么得到一个汉堡包售罄的坏消息,那我就得找点别的当午饭了。

所以Promise的出现其实是作为异步编程的一种解决方案。比传统的解决方案-回调函数和事件-更加合理、强大。

Promise的基本用法

var p1 = new Promise((resolve, reject) => {
 setTimeout(resolve, 1000, 'done');
 })
p1.then(data=>{
 console.log(data); // done
})

Promise一个明显的好处便是可以用来解决回调地狱。特别是在处理多个回调相互依赖的情况。

使用Promise解决多个异步依赖调用

Promise提供了一个方法Promise.all([p1,p2,p3]) ,用于将多个Promise实例,包装成一个新的Promise实例。接收的参数是一个数组,p1、p2、p3都是Promise对象。

此时Promise.all的状态取决于它的参数。

分两种情况:

  • p1、p2、p3的状态都是resolve的时候,Promise.all的状态才会变成resolve;
  • 只要p1、p2、p3中有一个的状态为reject,那么Promise.all的状态就会变成reject;

所以我们可以用Promise.all()来解决多个异步依赖调用。

比如我们平常经常遇到的一种情况:

网站中需要先获取用户名,然后再根据用户名去获取用户信息。这里获取用户名getUserName()和获取用户信息getUser()都是调用接口的异步请求。在获取用户信息之前,需要先获得用户名。也就是说getUser依赖于getUserName的状态。所以我们可以将这两个请求通过Promise.all()封装成一个新的Promise对象。

function getUserPromise(promiseX, promiseY){
 return Promise.all([promiseX, promiseY])
 .then(values =>
 // 返回的values由 promiseX 与 promiseY返回的值所构成的数组。
  values
 )
}
function getUserName(){
 let data = 'superman';
 return new Promise((resolve, reject) => {
  setTimeout(resolve(data), 1000);
 })
}
function getUser(){
 let data = {
 id:1,
 username: 'superman',
 gender: 'male'
 }
 return new Promise((resolve, reject) => {
 setTimeout(resolve(data), 2000);
 })
}
getUserPromise(getUserName(), getUser())
.then(data => {
 // 这里的data就是包含了getUserName 和 getUser返回值所组成的数组
 console.log(data); // [ 'superman', { id: 1, username: 'superman', gender: 'male' } ]
 })

使用Promise的链式调用

function getUserName(){
 let data = 'superman';
 return new Promise((resolve, reject) => {
 setTimeout(resolve(data), 4000);
 })
}
function getUser(username){
 let data = {
 id:1,
 username: 'superman',
 gender: 'male'
 }
 return new Promise((resolve, reject) => {
 if(username){
  setTimeout(resolve(data), 2000);
 }
 else{
  reject('err');
 }
 })
}
getUserName().then(username => {
 return getUser();
})
.then(user => {
 console.log(user);
})
.catch(err => {
 console.log(err);
})

有了Promise的链式调用,再也不同担心回调地狱的问题了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
学习ExtJS form布局
Oct 08 Javascript
JavaScript 入门基础知识 想学习js的朋友可以参考下
Dec 26 Javascript
js 禁止选择功能实现代码(兼容IE/Firefox)
Apr 23 Javascript
JavaScript高级程序设计(第3版)学习笔记2 js基础语法
Oct 11 Javascript
div当滚动到页面顶部的时候固定在顶部实例代码
May 27 Javascript
嵌入式iframe子页面与父页面js通信的方法
Jan 20 Javascript
表单元素值获取方式js及java方式的简单实例
Oct 15 Javascript
layui框架table 数据表格的方法级渲染详解
Aug 19 Javascript
JavaScript原型继承和原型链原理详解
Feb 04 Javascript
jquery实现手风琴案例
May 04 jQuery
解决vue打包报错Unexpected token: punc的问题
Oct 24 Javascript
手把手教你从零开始react+antd搭建项目
Jun 03 Javascript
js实现密码强度检验
Jan 15 #Javascript
JavaScript实现图像模糊化的方法实例
Jan 15 #Javascript
vue实现简单实时汇率计算功能
Jan 15 #Javascript
bootstrap——bootstrapTable实现隐藏列的示例
Jan 14 #Javascript
JS轮播图中缓动函数的封装
Nov 25 #Javascript
JavaScript字符串对象
Jan 14 #Javascript
jquery mobile移动端幻灯片滑动切换效果
Apr 15 #Javascript
You might like
使用数据库保存session的方法
2006/10/09 PHP
php定时计划任务的实现方法详解
2013/06/06 PHP
解析coreseek for sphinx的使用
2013/06/21 PHP
php分页示例分享
2014/04/30 PHP
php实现递归与无限分类的方法
2015/02/16 PHP
jQuery 技巧大全(新手入门篇)
2009/05/12 Javascript
通过location.replace禁止浏览器后退防止重复提交
2014/09/04 Javascript
jQuery常用数据处理方法小结
2015/02/20 Javascript
JS数组array元素的添加和删除方法代码实例
2015/06/01 Javascript
巧用Vue.js+Vuex制作专门收藏微信公众号的app
2016/11/03 Javascript
nodejs的HTML分析利器node-jquery用法浅析
2016/11/08 NodeJs
原生js实现addclass,removeclass,toggleclasss实例
2016/11/24 Javascript
webpack3+React 的配置全解
2017/08/21 Javascript
详解AngularJS跨页面传值(ui-router)
2017/08/23 Javascript
javascript 作用于作用域链的详解
2017/09/27 Javascript
JavaScript中关于class的调用方法
2017/11/28 Javascript
js中call()和apply()改变指针问题的讲解
2019/01/17 Javascript
基于vue3.0.1beta搭建仿京东的电商H5项目
2020/05/06 Javascript
springboot+vue+对接支付宝接口+二维码扫描支付功能(沙箱环境)
2020/10/15 Javascript
python与C互相调用的方法详解
2017/07/14 Python
python+pyqt实现右下角弹出框
2017/10/26 Python
Python函数的默认参数设计示例详解
2019/12/01 Python
如何解决tensorflow恢复模型的特定值时出错
2020/02/06 Python
opencv-python的RGB与BGR互转方式
2020/06/02 Python
python处理写入数据代码讲解
2020/10/22 Python
泰国最新活动和优惠:Megatix
2020/05/07 全球购物
西部世纪.net笔试题面试题
2014/04/03 面试题
国贸专业的职业规划书
2014/03/15 职场文书
如何写一份好的英文求职信
2014/03/19 职场文书
我为党旗添光彩演讲稿
2014/09/10 职场文书
2014年优质护理服务工作总结
2014/11/14 职场文书
汽车转让协议书
2015/01/29 职场文书
优秀创业计划书分享
2019/07/19 职场文书
请学会珍惜眼前,因为人生没有下辈子!
2019/11/12 职场文书
教你修复 Win11应用商店加载空白问题
2021/12/06 数码科技
python数字图像处理之图像的批量处理
2022/06/28 Python