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 ...
随机推荐
- Qt Installer Framework翻译(7-1)
配置文件 配置文件可自定义安装程序的用户界面和行为.该文件通常称为config.xml,位于config文件夹中. 最小配置文件由一个<Installer>根元素组成,<Name&g ...
- 双指针,BFS与图论(一)
(一)双指针 1.日志统计 小明维护着一个程序员论坛.现在他收集了一份”点赞”日志,日志共有 N 行. 其中每一行的格式是: ts id 表示在 ts 时刻编号 id 的帖子收到一个”赞”. 现在小明 ...
- UNIX 版本
一般UNIX系统都来源于AT&T公司的System V UNIX系统,BSD UNIX或其他类UNIX系统. System V UNIX:当今市场上大多数主要的商业UNIX系统都是基于AT&a ...
- Educational Codeforces Round 80 (Rated for Div. 2)部分题解
A. Deadline 题目链接 题目大意 给你\(n,d\)两个数,问是否存在\(x\)使得\(x+\frac{d}{x+1}\leq n\),其中\(\frac{d}{x+1}\)向上取整. 解题 ...
- CSS学习笔记--Div+Css布局(div+span以及盒模型)
1.DIV与SPAN 1.1简介 1.DIV和SPAN在整个HTML标记中,没有任何意义,他们的存在就是为了应用CSS样式 2.DIV和span的区别在与,span是内联元素,div是块级元素 内联元 ...
- js的new操作符深度解析
引言 我们都知道new操作符在js中一般是用来创建一个构造函数的实例,它在创建实例具体做了什么,MDN文档是这么说的: 我一开始看到,完全没有任何的头绪和理解,到底什么意思,后面通过上网查阅了大量的资 ...
- CAD制图系列之怎么画平行线
CAD怎么画平行线 输入O,点空格,输入距离100,选择已知的线,往你要偏移的方向就好! 具体方法如下:1.打开CAD制图 2.输入快捷键O 3.按下空格键 4.输入你所要的距离,例如12,并按下空格 ...
- Java并发编程(二):volatile关键字
volatile是Java虚拟机提供的轻量级的同步机制.volatile关键字有如下两个作用,一句话概括就是内存可见性和禁止重排序. 1)保证被volatile修饰的共享变量对所有线程总是可见的,也就 ...
- Harbor 1.9.x 版本从源码构建和运行
介绍 本指南为开发人员提供了从源代码构建和运行Harbor的说明. 步骤1:为Harbor的构建环境做准备 Harbor被部署为多个Docker容器,并且大多数代码都是用Go语言编写的.构建环境需要D ...
- CentOS 使用yum安装 pip
pip这个功能很不错,可以用来下载很多东西. 笔者使用的是CentOS Linux release 7.2.1511 (Core)这个版本. 查询版本的语句: cat /etc/redhat-rele ...