概述

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构造函数接受一个函数(既流程中第一步要执行的函数)作为参数,该函数的两个参数分别是resolvereject它们是两个函数,由 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 对象的更多相关文章

  1. ES6基础知识(Promise 对象)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. es6学习笔记--promise对象

    Promise对象是为了简化异步编程.解决回调地狱情况 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可 ...

  3. ES6系列_14之promise对象的简单使用

    1.产生原因 在前端开发中,最常见的的就是"回调",我相信很多人对于这个"回调"可谓是印象深刻呢.究其原因是因为层层回调会造成所谓的“回调地狱 (callbac ...

  4. js-ES6学习笔记-Promise对象(2)

    1.Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的.它的作用是为Promise实例添加状态改变时的回调函数. 2.Promise.pr ...

  5. js-ES6学习笔记-Promise对象

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

  6. ES6 - 基础学习(6): 对象扩展

    对象对于JavaScript至关重要,在ES6中对象又加了很多新特性. 对象字面量:属性的简洁表示法 ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值. let attr1 = & ...

  7. ES6 基础学习

    ECMAScript 6 标准入门 一.let和const let命令 let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效:是块级作用域,且let不允许 ...

  8. ES6 - 基础学习(1): 开发环境搭建

    现在Chrome浏览器已经很好的支持ES6了,但有些低版本的浏览器或其他浏览器还是不支持ES6的语法,因此实际项目开发或上线过程中就需要把ES6的语法转变成ES5的语法.项目开发过程中 Webpack ...

  9. python基础学习18----面向对象简述

    这里就不再讲面向对象的相关概念知识或者与面向过程的比较了,直接进入类的学习 1.类的创建 class people: def __init__(self):#构造函数 pass sfencs=peop ...

随机推荐

  1. [bzoj4524] [loj#2047] [Cqoi2016] 伪光滑数

    Description 若一个大于 \(1\) 的整数 \(M\) 的质因数分解有 \(k\) 项,其最大的质因子为 \(Ak\) ,并且满足 \(Ak^K \leq N\) , \(Ak<12 ...

  2. 机器学习-Tensorflow之Tensor和Dataset学习

    好了,咱们今天终于进入了现阶段机器学习领域内最流行的一个框架啦——TensorFlow.对的,这款由谷歌开发的机器学习框架非常的简单易用并且得到了几乎所有主流的认可,谷歌为了推广它的这个框架甚至单独开 ...

  3. NOI2.5 8783:单词接龙

    描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中 ...

  4. Docker在树莓派的安装与使用(Ubuntu Arm Server v19.10)

    最近由于冠状病毒疫情的原因,只能够和小朋友家里蹲.这几天把尘封已久的那个树莓派拿出来继续捣鼓.希望能够做一个异构的分布式系统框架,于是想把Docker也安装到树莓派上,以便后期做进一步的开发和实验. ...

  5. Dubbo入门到实战

    前沿:在当下流行的分布式架构中Dubbo是非常流行的一门技术,借着这几天有空学习学习,并在后面的项目中进行实战,为后面的分布式项目做铺垫. Dubbox简介 Dubbox 是一个分布式服务框架,其前身 ...

  6. ArrayList.subList方法使用总结

    ArrayList.subList方法使用总结 示例 List<String> list=new ArrayList<>(); list.add("d"); ...

  7. 浅显易懂的前端知识点(二)——HTTP协议基础

    HTTP 协议的初印象: 是基于 TCP/IP 协议的应用层协议,不涉及数据包的传输,主要规定了客户端和服务器之间的通信格式,默认使用 80 端口. 1 HTTP 协议 0.9 版(1991 年) 是 ...

  8. shiro 基础使用

    引 言 相关内容 : https://blog.csdn.net/superyayaya/article/details/94408805 在web 中, 不同角色的用户, 具有不同的访问权限, 有的 ...

  9. Nutz | Nutz项目整合Spring实战

    Nutz项目整合Spring实战 前言 Github地址 背景 实现步骤 加入springMvc与Spring 相关配置 新增Spring相关配置 新增SpringIocProvider 重写Nutz ...

  10. 深入JVM内存区域管理,值得你收藏

    JDK和JRE和JVM的关系 JDK(Java Development Kit)是程序开发者用来来编译.调试java程序用的开发工具包 JRE(JavaRuntimeEnvironment,Java运 ...