ES6语法——Promise对象
一、概念
Promise是异步编程的一种解决方案(解决回调地狱的问题),是一个能够获取异步操作信息的对象。Promise的内部保存着某个未来才会结束的事件(通常是一个异步操作)
二、特点
1.Promise对象的状态不受外界影响
Promise对象的状态由异步操作的结果决定当前处于pending(进行中)、fulfilled(已成功)还是rejected(已失败),任何其他操作都无法改变这个状态。
2.状态改变不可逆
一旦状态改变,就不会再变,任何时候都可以得到这个结果。promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。
3.缺点
(1)无法取消promise,一旦新建它就会立即执行,无法中途取消
(2)如果不设置回调函数,promise内部抛出的错误,不会反应到外部
(3)当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
4.优点
promise对象可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,promise对象提供统一的接口,使得控制异步操作更加容易。
三、基本用法
Promise对象是一个构造函数,接受一个函数为参数,这个函数的参数是resolve和reject,它们两个也是函数。
resolve函数的作用是,将promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去,外部用then方法接收
reject函数的作用是,将promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去,外部用catch方法接收
const promise = new Promise(function(resolve, reject) {
// ... some code if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
四、API详解
1.promise.prototype.then()
then方法是定义在原型对象promise.prototype上的,它是异步操作成功的回调函数,是resolve函数的外部接收器。参数是一个函数。
工作原理:当promise对象执行异步操作成功时,会通过resolve函数向外传递操作结果,由then方法接收后,对该结果继续执行传入then方法内部的函数。
then方法返回的是一个新的promise实例(注意,不是原来那个promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
function async(a,b) {
return new Promise(function (resolve,reject) {
//异步代码
setTimeout(function () {
//加入数据格式的判断
if(a!=undefined && (typeof a) =="number"){
//如果数据格式正确 则调用resolve匹配外部的then
resolve(a+b); }else{
//数据格式错误 调用reject 匹配外部的catch
reject(new Error("a is not a number,你瞎啊!!!")); } },200)
}); }
var promise=async(1,2);
promise.then(function (res) {
if(res>2){
console.log("我是3分支");
return async(res,3)
} //如果上一个then返回了一个promise 那么可以后面继续跟着then
}).then(function (res) {
if(res>4){
console.log("我是4分支");
return async(res,4);
} })
2.promise.prototype.catch()
catch方法的使用、原理同then方法,只是catch方法是失败的回调函数。
注意:
(1)如果没有使用catch()方法指定错误处理的回调函数,promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
(2)catch方法只能有一个,有多个无意义,后面的catch并不会执行,catch方法通常写在最后
var user=new User("niujinghui","123456");
user.checkUsername()
.then(function (res) {
return user.checkUserpwd();
})
.then(function (res) {
console.log("用户名密码都正确");
})
.catch(function (err) {
if(err) throw err;
});
3.promise.prototype.finally()
finally()方法用于指定不管 promise 对象最后状态如何,都会执行的操作。该方法是 es2018 引入标准的。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally方法源码
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
4.promise.all()
promise.all()用于将多个Promise实例包装成一个新的Promise实例。接受一个数组作为参数,如果该数组的元素不是promise对象实例,则使用Promise.resolve()方法将参数转为Promise实例再处理。另外,promise.all()方法的参数可以不是数组,但必须具有 iterator 接口,且返回的每个成员都是 promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中p的状态由p1、p2、p3决定,有以下两种情况:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(都成功,传返回值数组,如果没有返回值,会组成元素为undefined的数组)
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。(一失败,传reject的返回值)
注意!!坑点来袭
1、如果作为参数的 promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发promise.all()的catch方法。如果没有自己的catch方法,就会调用promise.all()的catch方法。
2、使用all()方法时,传入的promise对象如果本身定义了then和catch方法,因为这两个方法都会返回一个新的promise实例,所以调用all方法得到的新promise状态一直都是成功。解释起来有点绕,结合下面的代码看就知道了。
const p1 = new Promise((resolve,reject)=>{
let abc = 10
let a = 10;
let b = 20
if(abc > 30){
resolve(a+b)
}else{
reject(b-a)
}
}).then(function(res){
return res
}).catch(function(err){
console.log(err)
})
const p2 = new Promise((resolve,reject)=>{
let abc = 10
let a = 10;
let b = 20
if(abc > 30){
resolve(a+b+b)
}else{
reject(b-a-a)
}
}).then(function(res){
return res
}).catch(function(err){
console.log(err)
})
const p3 = new Promise((resolve,reject)=>{
let abc = 10
let a = 10;
let b = 20
if(abc > 30){
resolve(a*b)
}else{
reject(b/a)
}
}).then(function(res){
return res
}).catch(function(err){
console.log(err)
}) const p=Promise.all([p1,p2,p3])
p.then(function(){
console.log("正确")
}).catch(function(){
console.log("错误")
})
上面的代码在abc的值小于30时,就会执行reject方法,当调用promise.all()时,应该会输出错误。但是因为p1、p2、p3都有各自的then和catch方法,返回了新的promise实例,又因为这个新实例已经处于完成状态,所以变量p才会一直处于成功状态。(小炉写代码的时候还思考了好久,大坑!!!)
5.promise.race()
const p = Promise.race([p1, p2, p3]);
race方法的参数以及对参数中非promise对象的处理都和all方法一致,但是race方法返回的状态只和数组中最先改变状态的实例相同,那个最先改变的 promise 实例的返回值,就传递给p的回调函数。
注意:
(1)如果数组里面promise实例执行的速度一样,返回数组第一个promise执行的结果
(2)如果数组里面promise实例执行的速度不一样,返回最快的promise执行的结果,结果是失败就会直接匹配race的catch方法
(3)如果数组里面promise实例有成功、有失败的只要不是返回的结果,失败的就不影响
6.promise.allsettled()
promise.allsettled()方法接受一组 promise 实例作为参数,包装成一个新的 promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。该方法由 es2020 引入。
该方法返回的新的 promise 实例,一旦结束,状态总是fulfilled,不会变成rejected
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises); // 过滤出成功的请求
const successfulPromises = results.filter(p => p.status === 'fulfilled'); // 过滤出失败的请求,并输出原因
const errors = results
.filter(p => p.status === 'rejected')
.map(p => p.reason);
7.promise.any()
promise.any()跟promise.race()方法很像,只有一点不同,就是不会因为某个 promise 变成rejected状态而结束。如果所有的promise实例都是rejected,则返回AggregateError: All promises were rejected
经过小炉自己试验,总结规则如下:
(1)如果数组里面promise实例执行的速度不一样,执行最快的promise结果为成功则返回,为失败则按照这个规则找第二快的,依次类推。
(2)如果数组里面promise实例执行的速度一样,则返回第一个成功的promise的返回值
8.promise.resolve()
作用:将现有对象转为 Promise 对象
参数情况:
(1)参数是一个 Promise 实例
如果参数是 promise 实例,那么promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,promise.resolve方法会将这个对象转为 promise 对象,然后就立即执行thenable对象的then方法
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
}; let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。
(3)参数不是具有then方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则promise.resolve方法返回一个新的 promise 对象,状态为resolved。
(4)不带有任何参数
promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 promise 对象。
9.promise.reject()
promise.reject(reason)方法也会返回一个新的 promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了')) p.then(null, function (s) {
console.log(s)
});
注意:promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与promise.resolve方法不一致。
五、总结
1.promise的作用:Promise是异步编程的一种解决方案(解决回调地狱的问题)
2.无法取消promise,一旦新建它就会立即执行,无法中途取消
3.如果不设置回调函数,promise内部抛出的错误,不会反应到外部
4.当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
5.promise.then()成功的回调函数,返回的是一个新的promise实例,可以使用链式编程,参数来自resolve函数
6.promise。catch()失败的回调函数,只写一个,多写无意义,通常写在最后,参数来自reject函数
7.promise.all()监听所有的promise实例状态,全成功则成功,一失败则失败
8.promise.allsettled()监听所有的promise实例状态,等到所有这些参数实例都返回结果才结束,结束时状态总是fulfilled,不会变成rejected
9.promise.any()不会因为某个 promise 变成rejected状态而结束。如果所有的promise实例都是rejected,则返回AggregateError: All promises were rejected
10.promise.race()返回的状态只和数组中最先改变状态的实例相同,那个最先改变的 promise 实例的返回值,就传递给p的回调函数。
11.promise.finally()不管 promise 对象最后状态如何,都会执行的操作
12.promise.resolve()和promise.reject()都返回一个promise实例,但是promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数
ES6语法——Promise对象的更多相关文章
- ES6的promise对象研究
ES6的promise对象研究 什么叫promise? Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码:让代码更加的直观. 那我们为什么 ...
- ES6语法 promise用法
ES6语法 promise用法 function doSomething(){ return new Promise((resolve,reject)=>{ resolve('jjjj');// ...
- 教你如何使用ES6的Promise对象
教你如何使用ES6的Promise对象 Promise对象,ES6新增的一个全新特性,这个是 ES6中非常重要的一个对象 Promise的设计初衷 首先,我们先一起了解一下,为什么要设计出这么一个玩意 ...
- ES6的Promise对象
http://es6.ruanyifeng.com/#docs/promise Promise 对象 Promise 的含义 基本用法 Promise.prototype.then() Promise ...
- ES6的promise对象应该这样用
ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...
- ES6 - promise对象
Promise的设计初衷 我们使用ajax请求数据,得到数据后再对数据进行操作,可是有时候,对得到的数据进行操作的过程中,可能又要用到ajax请求,这时,我们的代码就变成了这样: $.ajax({ s ...
- ES6中Promise对象个人理解
Promise是ES6原生提供的一个用来传递异步消息的对象.它减少了传统ajax金字塔回调,可以将异步操作以同步操作的流程表达出来使得代码维护和可读性方面好很多. Promise的状态: 既然是用来传 ...
- 前端知识点回顾之重点篇——ES6的Promise对象
Promise Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大. 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异 ...
- 谈谈 ES6 的 Promise 对象
https://segmentfault.com/a/1190000002928371 前言 开篇首先设想一个日常开发常常会遇到的需求:在多个接口异步请求数据,然后利用这些数据来进行一系列的操作.一般 ...
随机推荐
- ObjectOutputStream和ObjectInputStream对对象进行序列化和反序列化
1 Java序列化和反序列化简介 Java序列化是指把对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为java对象的过程. 我们把对象序列化成有序字节流,保存到本地磁盘或者Redis等 ...
- MySQL实战45讲笔记一
MySQL的基本架构大体可以分为server层和存储引擎层,逻辑架构图如下: Server层除了图中显示的,还包括所有的内置函数(包括日期.时间.数学和加密函数等),存储过程.触发器.视图等跨存储引擎 ...
- 小师妹学JVM之:JIT中的PrintCompilation
目录 简介 PrintCompilation 分析PrintCompilation的结果 总结 简介 上篇文章我们讲到了JIT中的LogCompilation,将编译的日志都收集起来,存到日志文件里面 ...
- 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- ajax前后端交互原理(4)
4.JSON 4.1 什么是JSON? JavaScript 对象表示法(JavaScript Object Notation)简称JSON,是一种轻量级的数据交换格式.虽然它基于JavaScript ...
- LeetCode63. 不同路径 II
这题和62题类似,只不过这里多了障碍物,只需要把有障碍物的格子的方案数设置为0即可,其他格子还是原来的走法. class Solution { public: int uniquePathsWithO ...
- Java 线程基础,从这篇开始
线程作为操作系统中最少调度单位,在当前系统的运行环境中,一般都拥有多核处理器,为了更好的充分利用 CPU,掌握其正确使用方式,能更高效的使程序运行.同时,在 Java 面试中,也是极其重要的一个模块. ...
- YOLO-V3实战(darknet)
一. 准备工作 1)实验环境: darknet 是由 C 和 CUDA 开发的,不需要配置其他深度学习的框架(如,tensorflow.caffe 等),支持 CPU 和 GPU 运算,而且安装过程非 ...
- python基础知识练习1
1.要求:输入A.B.C获得方程的解. 分析:通过input函数接收A,B,C的值.通过公式计算出detal的值,再根据条件进行判断,输出所需要的值: def args_input(): try: A ...
- Spring Boot中的事务是如何实现的
本文首发于微信公众号[猿灯塔],转载引用请说明出处 今天呢!灯塔君跟大家讲: Spring Boot中的事务是如何实现的 1. 概述 一直在用SpringBoot中的@Transactional来做事 ...