教你如何使用ES6的Promise对象

Promise对象,ES6新增的一个全新特性,这个是 ES6中非常重要的一个对象

Promise的设计初衷

首先,我们先一起了解一下,为什么要设计出这么一个玩意儿,用它是为了解决什么问题?

带着这个问题,我们来回想一下日常开发中,经常需要用到ajax请求数据,拿到数据后,再进行一些处理。

可有一次,你需要用ajax进行多次请求,而且,每次请求都依赖上一次请求返回的数据来作为参数,然后继续发出请求,你把代码写成了这样:

    //------请求A 开始---------
$.ajax({
success:function(res1){ //------请求B 开始----
$.ajax({
success:function(res2){ //----请求C 开始---
$.ajax({
success:function(res3){
}
});
//---请求C 结束--- }
});
//------请求B 结束----- }
});
//------请求A 结束---------

上面的案例,假设请求C需要依赖请求B返回的数据,所以,C只能放在B的success函数内;B需要依赖A请求得到的数据作为参数,所以,B只能放在A的success函数内;也就是:请求A包含着请求B,请求B又包含了请求C。

就这样,请求顺序为:请求A -> 请求B -> 请求C,最后你也能顺利的完成了任务。

传统写法的不足

但是这样写,会有一些缺点:

1. 如果存在多个请求操作层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也越来越差,不直观,调试起来也不方便。如果多人开发的时候没有足够的沟通协商,大家的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便。

2. 如果请求C的需要依赖A和B的结果,但是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间。

既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。

那么我们就知道了:Pro****mise对象能使我们更合理、更规范地进行处理异步操作。

Promise的基本用法

接下来,我们就看看它的基本用法:

    let pro = new Promise(function(resolve,reject){
//....
});

Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve和reject,两个函数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。

Promise的是三种状态

Promise对象有三种状态:

  1. pending:刚刚创建一个Promise实例的时候,表示初始状态;

  2. fulfilled:resolve方法调用的时候,表示操作成功;

  3. rejected:reject方法调用的时候,表示操作失败;

状态只能从 初始化 -> 成功 或者 初始化 -> 失败,不能逆向转换,也不能在成功fulfilled 和失败rejected之间转换。

    let pro = new Promise(function(resolve,reject){
//实例化后状态:pending if('操作成功'){
resolve();
//resolve方法调用,状态为:fulfilled
}else{
reject();
//reject方法调用,状态为:rejected
}
});

上面的注释,讲清楚了一个Promise实例的状态改变情况。

初始化实例后,对象的状态就变成了pending;当resolve方法被调用的时候,状态就变成了:成功fulfilled;当reject方法被调用的时候,状态就会有pending变成失败rejected。

then( )方法

了解了Promise的创建和状态,我们来学习一个最重要的实例方法:then( )方法。

then( )方法:用于绑定处理操作后的处理程序。


pro.then(function (res) {
//操作成功的处理程序
},function (error) {
//操作失败的处理程序
});

参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作异常后的业务。

catch( )方法

对于操作异常的程序,Promise专门提供了一个实例方法来处理:catch( )方法。

    pro.catch(function (error) {
//操作失败的处理程序
});

catch只接受一个参数,用于处理操作异常后的业务。

综合上面的两个方法,大家都建议将then方法用于处理操作成功,catch方法用于处理操作异常,也就是:

    pro.then(function (res) {
//操作成功的处理程序
}).catch(function (error) {
//操作失败的处理程序
});

之所以能够使用链式调用,是因为then方法和catch方法调用后,都会返回promise对象。

讲了那么多,如果你之前一点都没接触过Promise的话,现在一定很懵逼,没关系,下面我们用一个案例来串联前面的知识点,演示一下,认真阅读注释:

    //用new关键字创建一个Promise实例
let pro = new Promise(function(resolve,reject){
//假设condition的值为true
let condition = true; if(condition){
//调用操作成功方法
resolve('操作成功');
//状态:pending->fulfilled
}else{
//调用操作异常方法
reject('操作异常');
//状态:pending->rejected
}
}); //用then处理操作成功,catch处理操作异常
pro.then(function (res) { //操作成功的处理程序
console.log(res) }).catch(function (error) { //操作失败的处理程序
console.log(error) });
//控制台输出:操作成功

上面案例的注释十分详细,串联起了上面介绍的所有知识点:创建实例,状态转换,then方法和catch方法的使用。

由于我们设置了变量condition的值为true,所以执行后控制台输出的结果是:“操作成功”。

上面就是Promise用于处理操作异常的这个过程;但是,正如文章开头讲到的,如果多个操作之间层层依赖,我们用Promise又是怎么处理的呢?

完整案例

我们看看下面的案例,代码有点长,但是一点都不复杂:

    let pro = new Promise(function(resolve,reject){

        if(true){
//调用操作成功方法
resolve('操作成功');
}else{
//调用操作异常方法
reject('操作异常');
}
}); //用then处理操作成功,catch处理操作异常
pro.then(requestA)
.then(requestB)
.then(requestC)
.catch(requestError); function requestA(){
console.log('请求A成功');
return '请求B,下一个就是你了';
}
function requestB(res){
console.log('上一步的结果:'+res);
console.log('请求B成功');
return '请求C,下一个就是你了';
}
function requestC(res){
console.log('上一步的结果:'+res);
console.log('请求C成功');
}
function requestError(){
console.log('请求失败');
} //打印结果:
//请求A成功
//上一步的结果:请求B,下一个就是你了
//请求B成功
//上一步的结果:请求C,下一个就是你了
//请求C成功

案例中,先是创建一个实例,还声明了4个函数,其中三个是分别代表着请求A,请求B,请求C;有了then方法,三个请求操作再也不用层层嵌套了。我们使用then方法,按照调用顺序,很直观地完成了三个操作的绑定,并且,如果请求B依赖于请求A的结果,那么,可以在请求A的程序用使用return语句把需要的数据作为参数,传递给下一个请求,案例中我们就是使用return实现传递参数给下一步操作的。

更直观的图解

如果你还是是懂非懂,没关系,前端君拼了,上图:

图有点粗糙,但是能反应出上面程序的执行过程,帮助大家加深理解。

除了提供了实例方法以外,Promise还提供了一些类方法,也就是不用创建实例,也可以调用的方法。

下面,我们来学习几个重要的。

Promise.all( )方法

Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。

我们来演示一下:

    //创建实例pro1
let pro1 = new Promise(function(resolve){
setTimeout(function () {
resolve('实例1操作成功');
},5000);
}); //创建实例pro2
let pro2 = new Promise(function(resolve){
setTimeout(function () {
resolve('实例2操作成功');
},1000);
}); Promise.all([pro1,pro2]).then(function(result){
console.log(result);
});
//打印结果:["实例1操作成功", "实例2操作成功"]

上述案例,我们创建了两个Promise实例:pro1和pro2,我们注意两个setTimeout的第二个参数,分别是5000毫秒和1000毫秒,当我们调用Promise.all( )方法的时候,会延迟到5秒才控制台会输出结果。

因为1000毫秒以后,实例pro2进入了成功fulfilled状态;此时,Promise.all( )还不会有所行动,因为实例pro1还没有进入成功fulfilled状态;等到了5000毫秒以后,实例pro1也进入了成功fulfilled状态,Promise.all( )才会进入then方法,然后在控制台输出:["实例1操作成功","实例2操作成功"]。

这个方法有什么用呢?一般这样的场景:我们执行某个操作,这个操作需要得到需要多个接口请求回来的数据来支持,但是这些接口请求之前互不依赖,不需要层层嵌套。这种情况下就适合使用Promise.all( )方法,因为它会得到所有接口都请求成功了,才会进行操作。

Promise.race( )方法

另一个类似的方法是Promise.race()方法:它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。

    //初始化实例pro1
let pro1 = new Promise(function(resolve){
setTimeout(function () {
resolve('实例1操作成功');
},4000);
}); //初始化实例pro2
let pro2 = new Promise(function(resolve,reject){
setTimeout(function () {
reject('实例2操作失败');
},2000);
}); Promise.race([pro2,pro1]).then(function(result){
console.log(result);
}).catch(function(error){
console.log(error);
});
//打印结果:实例2操作失败

同样是两个实例,实例pro1不变,不同的是实例pro2,这次我们调用的是失败函数reject。

由于pro2实例中2000毫秒之后就执行reject方法,早于实例pro1的4000毫秒,所以最后输出的是:实例2操作失败。

以上就是对Promise对象的内容讲解,上面提到了一个概念:回调地狱;指的是过多地使用回调函数嵌套,使得调试和维护起来极其的不便。

下面给大家看个真正的回调地狱,前方高能,图慎点:

总结:Promise是一个让开发者更合理、更规范地用于处理异步操作的对象,

它有三种状态:初始化、操作成功、操作异常。

使用实例方法:then( ) 和 catch( ) 来绑定处理程序;

还提供了类方法:Promise.all( ) 和 Promise.race( )。

教你如何使用ES6的Promise对象的更多相关文章

  1. ES6的promise对象研究

    ES6的promise对象研究 什么叫promise? Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码:让代码更加的直观. 那我们为什么 ...

  2. ES6的promise对象应该这样用

    ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...

  3. ES6 - promise对象

    Promise的设计初衷 我们使用ajax请求数据,得到数据后再对数据进行操作,可是有时候,对得到的数据进行操作的过程中,可能又要用到ajax请求,这时,我们的代码就变成了这样: $.ajax({ s ...

  4. ES6中Promise对象个人理解

    Promise是ES6原生提供的一个用来传递异步消息的对象.它减少了传统ajax金字塔回调,可以将异步操作以同步操作的流程表达出来使得代码维护和可读性方面好很多. Promise的状态: 既然是用来传 ...

  5. ES6的Promise对象

    http://es6.ruanyifeng.com/#docs/promise Promise 对象 Promise 的含义 基本用法 Promise.prototype.then() Promise ...

  6. 前端知识点回顾之重点篇——ES6的Promise对象

    Promise Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大. 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异 ...

  7. 谈谈 ES6 的 Promise 对象

    https://segmentfault.com/a/1190000002928371 前言 开篇首先设想一个日常开发常常会遇到的需求:在多个接口异步请求数据,然后利用这些数据来进行一系列的操作.一般 ...

  8. ES6 用Promise对象实现的 Ajax 操作

    下面是一个用Promise对象实现的 Ajax 操作的例子. const getJSON = function(url) { const promise = new Promise(function( ...

  9. ES6之Promise对象

    创建Promise对象 function getHtml(url) { return new Promise((resolve, reject) => { let xhr = new XMLHt ...

随机推荐

  1. 【SpringBoot】 中时间类型 序列化、反序列化、格式处理

    [SpringBoot] 中时间类型 序列化.反序列化.格式处理 Date yml全局配置 spring: jackson: time-zone: GMT+8 date-format: yyyy-MM ...

  2. 详解 CmProcess 跨进程通信的实现

    CmProcess 是 Android 一个跨进程通信框架,整体代码比较简单,总共 20 多个类,能够很好的便于我们去了解跨进程实现的原理. 个人猜测 CmProcess 也是借鉴了 VirtualA ...

  3. C++语法小记---如何判断一个变量是不是指针

    如何判断一个变量是不是指针? 思路:模板函数 + 可变参数 + sizeof(函数) #include <iostream> #include <string> using n ...

  4. JSON.stringify和JSON.parse的用法

    用法概述 所有的现代浏览器都支持 JSON 对象,有两个非常有用的方法来处理 JSON 格式的内容: JSON.parse(string) 接受一个 JSON 字符串并将其转换成一个 JavaScri ...

  5. [jvm] -- 引用篇

    四种引用及其应用场景 强引用 强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收. 使用场景:啥时候都在使用 软引用 软引用在程序内存不足时,会被回收. 使用场景:创建缓存 ...

  6. Ubuntu安装Docker(官方文档翻译)

    翻译自Docker官方文档 https://docs.docker.com/engine/installation/linux/ubuntulinux/ 之前因为看不懂官方文档,卡在某个步骤无法完成安 ...

  7. PHP代码实现二分法查找

    需求:定义一个函数接收一个数组对象和一个要查找的目标元素,函数要返回该目标元素在数组中的索引值,如果目标元素不存在数组中,那么返回-1表示. //折半查找法(二分法): 使用前提必需是有序的数组. / ...

  8. php 导出数据到excel类

    原文链接地址:http://www.oschina.net/code/snippet_212240_21885 标注:在使用时一定要屏蔽掉//$bodyVal = $this->charset( ...

  9. 编写优美Android注释的常用语法

    编写优美Android注释的常用语法   短期目标是定期能出一篇简文,希望自己能坚持下去~~~~( ̄_, ̄ )   附上Android君 今天要分享的是关于Android注释系统的一些强大功能!! 实 ...

  10. 花生壳内网穿透vue项目错误

    原因:新版的webpack-dev-server出于安全考虑,默认检查hostname,如果hostname不是配置内的,将中断访问. 解决:webpack.dev.conf.js添加配置 disab ...