ES6 - 基础学习(8): Promise 对象
概述
Promise是异步编程的一种解决方案,比传统的解决方案(多层嵌套回调、回调函数和事件)更强大也更合理。从语法上说,Promise是一个对象,从它可以获取异步操作的消息,Promise 还提供了统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise的出现很好的解决了回调地狱这一难题,在之前ES5中多层嵌套回调时,回调代码层次过多,嵌套太深,时间久了既不利于相关代码的理解也不利于代码后期维护以及后续迭代开发,因此Promise才尤为重要。
Promise状态
状态特点:
1、Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)、 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。
2、Promise 对象状态只有两种变化形式:从 pending 变为 fulfilled 或从 pending 变为 rejected。只要Promise 对象处于 fulfilled 或 rejected 状态,Promise 对象状态就不会再改变(即 resolved(已定型))。
状态缺点:
1、无法取消Promise ,Promise一旦建立就会立即执行,且中途无法取消。
2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部,Promise会吃掉自己的错误。
3、当处于 pending(进行中) 状态时,无法得知 Promise目前进展到哪一个阶段(是刚刚开始还是即将完成)。
Promise用法
ES6中,Promise对象是一个构造函数,用来生成Promise实例。Promise构造函数接受一个函数(既流程中第一步要执行的函数)作为参数,该函数的两个参数分别是resolve和reject,它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
let state = true;
let promise = new Promise(function (resolve, reject) {
// ... do something
if (state) { // 异步操作成功
resolve(value); // resolve函数:将 Promise 对象状态从"进行中"变为"已成功"(即从 pending 变为 fulfilled),在异步操作成功后调用,并将异步操作返回的结果,作为参数传递出去;
} else { // 异步操作失败
reject(error); // reject函数:将 Promise 对象状态从"进行中"变为"已失败"(即从 pending 变为 rejected),在异步操作失败后调用,并将异步操作产生的错误,作为参数传递出去。
}
});
/* 或者分开写 */
// 流程中第一步要执行的函数,即 Promise 构造函数接受的参数函数
let step1 = function (resolve, reject) {
// ... do something
if (state) { // 异步操作成功
resolve(value); // resolve函数:将 Promise 对象状态从"进行中"变为"已成功"(即从 pending 变为 fulfilled),在异步操作成功后调用,并将异步操作返回的结果,作为参数传递出去;
} else { // 异步操作失败
reject(error); // reject函数:将 Promise 对象状态从"进行中"变为"已失败"(即从 pending 变为 rejected),在异步操作失败后调用,并将异步操作产生的错误,作为参数传递出去。
}
};
let promise = new Promise(step1);
Promise 实例方法
Promise 实例提供了很多其他方法, 这些方法基本都定义在原型对象 Promise.prototype 上。
then 方法:then方法返回的是一个新的Promise实例(从参数就可看出,第二个Promise实例执行的是第二步了),因此then方法可以采用链式写法,即then方法后再调用另一个then方法。
/* then方法 */
let state = true;
function step1(resolve, reject) {
console.log('第一步开始');
if (state) {
resolve('第一步执行成功!');
} else {
reject('第一步执行失败!');
}
}
function step2(resolve, reject) {
console.log('第二步开始');
if (state) {
resolve('第二步操作成功!');
} else {
reject('第二步操作失败!');
}
} // Promise实例生成后,在实例 then方法内分别指定 resolved状态 和 rejected状态的回调函数。
// then方法接受两个回调函数作为参数,第一个回调函数是Promise对象状态变为resolved时调用,第二个回调函数是Promise对象状态变为rejected时调用。其中,第二个函数是可选参数,非必须提供,这两个函数都接受Promise对象传出的值作为参数。
new Promise(step1).then(function (value) {
console.log(value); // 第一步执行成功!
state = false;
return new Promise(step2); // 返回的是一个新的Promise实例(从参数就可看出,第二个Promise实例执行的是第二步了),因此then方法可以采用链式写法,即then方法后再调用另一个then方法。
}).then(function (value) { // 新Promise实例的then方法(链式写法)
console.log(value); // 第二步操作成功!
}, function (value) {
console.log(value); // 第二步操作失败!
});

catch 方法:catch方法是 .then(null, rejection) 或 .then(undefined, rejection) 的别名,用于指定异步操作发生错误时的回调函数。
/* catch方法 */
let state = false;
function step1(resolve, reject) {
console.log('第一步开始');
if (state) {
resolve('第一步执行成功!');
} else {
reject('第一步执行失败!');
}
} new Promise(step1).then(function (value) {
console.log(value);
}).catch(function (error) {
console.log('Promise发生错误:', error);
});
// new Promise(step1)返回一个Promise对象,如果该对象状态变为resolved,则调用then方法指定的回调函数;
// 如果异步操作抛出错误,状态就会变为rejected,则调用catch方法指定的回调函数,处理这个错误。同时 then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。
let promiseError = new Promise(function (resolve, reject) {
// throw new Error('Promise抛出的错误!');
reject(new Error('test')); // reject方法的作用,在这等同于throw,都是抛出错误
});
promiseError.catch(function(error) {
console.log(error);
}); // Promise对象产生的错误如果不处理(即没有catch方法回调函数处理),Promise对象抛出的错误也不会传递到外层代码,并不会影响外层代码的执行(即系统不会有任何反应,原进程照常执行,不会中断和退出)。
// 这与传统的try/catch代码块不同,会一直向后(冒泡)传递,直到被catch捕获为止。
let promiseCatch = new Promise(function (resolve, reject) {
reject(xx) // Promise对象异步操作失败,传出未声明参数
});
promiseCatch.catch(function(error) {
console.log(error);
console.log(xxxx); // catch中未声明参数
});
setTimeout(function () {
console.log('系统照常执行,并未受到影响!');
},2000);

// 如果 Promise对象状态已经变成resolved,则无论是抛出错误还是reject传出错误,都是无效的。操作不会执行,参数传递不出去。
let promiseError = new Promise(function (resolve, reject) {
resolve("It's resolved!"); // Promise对象状态已经变成resolved。
throw new Error("It's rejected!");
reject(new Error("It's rejected!"));
});
promiseError.then(function (value) {
console.log(value); // It's resolved!
}).catch(function (error) {
console.log(error);
});

// 不管 Promise对象后面跟了多少个 then方法,建议最后用catch方法结尾,这样不但可以处理 Promise对象内部发生的错误,还可以处理流程过程中 then方法报出的错误。
// 1、最后一步不跟catch方法
function step1(resolve, reject) {
resolve(xx); // xx变量 未声明
}
function step2(resolve, reject) {
reject(yyyy); // yyyy变量 未声明
} new Promise(step1).then(function(value) { // 由于xx变量未声明,此处then方法不执行,Promise对象异步执行报出的错误被下面catch方法捕获
console.log(value);
}).catch(function(error) {
console.log('catch捕获到错误:', error); // catch捕获到错误: ReferenceError: xx is not defined
}).then(function() {
return new Promise(step2)
}).then(function(value) { // 同样yyyy变量也未声明,此处then方法不执行,但后面没有其他catch方法,所以 step2报出的错误将不会被捕获,也不会得到处理
console.log(value);
}); // 2、最后一步跟catch方法
function step1(resolve, reject) {
resolve(xx);
}
function step2(resolve, reject) {
reject(yyyy);
} new Promise(step1).then(function(value) {
console.log(value);
}).then(function() {
console.log('貌似你没被执行!');
return new Promise(step2)
}).then(function(value) {
console.log(value);
}).catch(function(error) {
console.log('catch捕获到错误:', error); // catch捕获到错误: ReferenceError: xx is not defined
});
// 从打印可以看出,catch方法捕获到了错误(系统执行报出的第一个错误),同时中断后续代码(后续流程)执行。

图1:最后一步不跟catch方法 图2:最后一步跟catch方法
ES6 - 基础学习(8): Promise 对象的更多相关文章
- ES6基础知识(Promise 对象)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- es6学习笔记--promise对象
Promise对象是为了简化异步编程.解决回调地狱情况 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可 ...
- ES6系列_14之promise对象的简单使用
1.产生原因 在前端开发中,最常见的的就是"回调",我相信很多人对于这个"回调"可谓是印象深刻呢.究其原因是因为层层回调会造成所谓的“回调地狱 (callbac ...
- js-ES6学习笔记-Promise对象(2)
1.Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的.它的作用是为Promise实例添加状态改变时的回调函数. 2.Promise.pr ...
- js-ES6学习笔记-Promise对象
1.Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 2.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作) ...
- ES6 - 基础学习(6): 对象扩展
对象对于JavaScript至关重要,在ES6中对象又加了很多新特性. 对象字面量:属性的简洁表示法 ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值. let attr1 = & ...
- ES6 基础学习
ECMAScript 6 标准入门 一.let和const let命令 let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效:是块级作用域,且let不允许 ...
- ES6 - 基础学习(1): 开发环境搭建
现在Chrome浏览器已经很好的支持ES6了,但有些低版本的浏览器或其他浏览器还是不支持ES6的语法,因此实际项目开发或上线过程中就需要把ES6的语法转变成ES5的语法.项目开发过程中 Webpack ...
- python基础学习18----面向对象简述
这里就不再讲面向对象的相关概念知识或者与面向过程的比较了,直接进入类的学习 1.类的创建 class people: def __init__(self):#构造函数 pass sfencs=peop ...
随机推荐
- Hystrix 监控数据聚合 Turbine【Finchley 版】
原文地址:https://windmt.com/2018/04/17/spring-cloud-6-turbine/ 上一篇我们介绍了使用 Hystrix Dashboard 来展示 Hystrix ...
- python接口自动化测试 - openpyxl封装类
前言 为了更好的让openpyxl在工作中使用,将openpyxl的常用操作封装起来,这样不仅复用性高,而且阅读性好 直接上代码 #!/usr/bin/env python # -*- coding: ...
- jquery的版本 纵多 , 各个版本的插件的融合 ,
有些插件在哪些版本下没有 插件之间因为版本冲突 是得不偿失的事情
- Object类、常用API_2
主要内容 Object类 Date类 DateFormat类 Calendar类 System类 StringBuilder类 包装类 学习目标 -[ ] 能够说出Object类的特点 -[ ] 能够 ...
- API文档自动生成,Swagger的配置
ASP.NET的部署方式 第一步:引用程序集 打开NuGet程序包管理器,搜索Swagger,安装第一个,注意画圈的地方, 已经包含主程序和UI了,安装完成后会在根目录App_Start文件夹下生成S ...
- 理想乡题解 (线段树优化dp)
题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注 ...
- 利用在线绘制3d几何图形工具分析投影变化
业余写了个在线绘制几何图形工具,工具链接如下: https://tinygltf.xyz/drawgeometry/ 通过脚本代码在可视化窗口添加对应的点,线段,成像平面推到投影后坐标的计算: 点A通 ...
- apache和nginx那点事儿--阻塞和异步
先明白的事儿:当一个程序在执行的时候,一般会创建一个进程,也可以有多个进程.一个进程至少会创建一个线程,多个线程共享一个程序进程的内存.程序的运行最终是靠线程来完成操作的.线程的数量跟CPU核数有关, ...
- VirtualBox 虚拟机 从入门到入坑
...
- 使用RKE快速部署k8s集群
一.环境准备 1.1环境信息 IP地址 角色 部署软件 10.10.100.5 K8s Master Etcd.Control 10.10.100.17 K8s Worker1 Worker 10.1 ...