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 ...
随机推荐
- Codeforces940掉分记
掉分经过 难得这次时间比较好,下午17:35开始. 本来还很高兴,心想这回肯定不会犯困,没准排名能再上升一些呢,,可惜事与愿违-- 上来a题,光看懂题就花了一些时间. 然后开始写,结果第一遍CE,第二 ...
- Wordpress4.9.6 任意文件删除漏洞复现分析
第一章 漏洞简介及危害分析 1.1漏洞介绍 WordPress可以说是当今最受欢迎的(我想说没有之一)基于PHP的开源CMS,其目前的全球用户高达数百万,并拥有超过4600万次的超高下载量.它是一个开 ...
- 「 Android开发 」开启第一个App应用
每天进步一丢丢,连接梦与想 无论什么时候,永远不要以为自己知道一切 -巴普洛夫 最近玩了下Android,但遇到了一些坑,浪费了很多的时间,在此记录一下,你若是遇到了就知道怎么解决了 PS:建议使 ...
- 时间序列数据库(TSDB)初识与选择
时间序列数据库(TSDB)初识与选择 本文作者由 MageByte 团队的 「借来方向」编写,关注公众号 给你更多硬核技术 背景 这两年互联网行业掀着一股新风,总是听着各种高大上的新名词.大数据.人工 ...
- springboot中使用Caffeine本地缓存
Caffeine是使用Java8对Guava缓存的重写版本性能有很大提升 一 依赖 <dependency> <groupId>org.springframework.boot ...
- Lambda 表达式入门,看这篇就够了
说出来怕你们不相信,刚接到物业通知,疫情防控升级了,车辆只能出不能进,每户家庭每天可指派 1 名成员上街采购生活用品.这不是谣言,截个图自证清白,出自洛阳市湖北路街道处. 看来事态严峻,这样看似好心, ...
- Arduino系列之智能家居蓝牙语音遥控灯(四)
用到的材料 Arduino uno hc-05 蓝牙模块 安卓手机 安卓APP AMR—voice 通过安卓手机连接Arduino的蓝牙模块Hc-05,通过语音识别软件AMR-voice识别语音, ...
- 【搞定面试官】- Synchronized如何实现同步?锁优化?(1)
前言 说起Java面试中最高频的知识点非多线程莫属.每每提起多线程都绕不过一个Java关键字--synchronized.我们都知道该关键字可以保证在同一时刻,只有一个线程可以执行某个方法或者某个代码 ...
- Comb结合android开发
https://blog.csdn.net/qq_29665509/article/details/79272441 参考comb官方文档 https://blog.csdn.net/qq_29665 ...
- char*a[10] ={"123456","2345"}和char*a="abcde"