Promise 让人又恨又爱的存在,恨是由于面试的时候会围绕它出不少题,又绕又头疼,爱是真香,谁都逃不过真香定律。前端
Promise 是异步编程的一个新的解决方案,阮一峰:ECMAScript 6 入门中给出对 promise 的含义是:所谓 Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。 Promise 是一个构造函数,它有两个特色:git
一般咱们来讲,Promise 主要是解决异步回调地狱。什么是回调地狱?
es6
从网上找了几张图,你们能够感觉一下被回调地狱所支配的恐惧: 回调地狱最大的缺点就是代码可读性差,编写费劲。 接下来咱们来看一下 Promise 的基本用法:github
new Promise((resolve, reject)=>{
... if(success) { resolve(value); }else { reject(error); } }) 复制代码
以前说过,Promise 是一个构造函数,它接收一个函数参数,这个函数中接收两个参数,一个是 resolve 还有一个是 rejected,这两个参数均为函数,而且这两个参数不用本身部署,JS 引擎会自动部署。 resolve 函数的做用是当异步函数成功时,将成功后的值传递出去,同时也是将状态从 pending 变为 resolved,reject 函数的做用是当异步函数失败后,将失败的错误信息传递出去,同时也是将状态从 pending 变为 rejected。面试
当 Promise 实例建立成功后,能够执行其原型上的 then 方法,then 方法一样接收两个函数参数,第一个是接收的 resolve 回调的结果,第二个是 reject 回调的结果,第二个参数是非必填的。编程
new Promise((resolve, reject) => {
resolve(1); }).then( (value) => console.log(value) // 1 ); new Promise((resolve, reject) => { reject("出现错误"); }).then( (error) => console.log(error) // 出现错误 ); 复制代码
由于 Promise 的对象时当即建立的,因此在 resolve 和 reject 函数以前的操做都会当即执行:数组
new Promise((resolve, reject) => {
console.log(2); resolve(1); }).then( (value) => console.log(value) // 2 1 ); 复制代码
Promise 执行 then 方法后会返回回来一个新的 Promise 对象,因此能够采用链式调用。promise
new Promise((resolve) => {
resolve(1); }) .then((value) => value + 1) .then((value) => console.log(value)); // 2 复制代码
第一个 then 函数的返回值,能够做为参数传给第二个 then 函数。若是第一个 then 函数返回的依旧是一个 Promise 对象呢?便是一个 Promise 封装的异步操做:markdown
new Promise((resolve) => {
resolve(1); }) .then( (value) => new Promise((resolve) => { resolve(3); }) ) .then((value) => console.log(value)); // 3 复制代码
此时第二个 then 函数传入的参数,即为第一个 then 函数返回的 Promise 对象的 resolved 状态下传递的值。也能够说只有第一个 then 返回的 Promise 执行状态成功时,第二个 then 函数才会执行。异步
除了 then 函数外,在 Promise 原型上还有一个 catch 函数,此函数时当 Promise 内部异步出现错误的时候即为 rejected 状态时,才执行。
new Promise((resolve, reject)=>{
throw new Error('test') }).catch(err=>console.log(err)) // Error: test 等同于: new Promise((resolve, reject)=>{ throw new Error('test') }).then(null, err=>console.log(err)) // Error: test 复制代码
当 then 第二个参数和 catch 函数同时存在时,将不会执行 catch 函数:
new Promise((resolve, reject) => {
throw new Error("test"); }) .then(null, (err) => console.log(err)) // Error: test .catch((err) => console.log(err)); 复制代码
那此时的 catch 捕获的是哪一个 Promise 的错误呢?捕获的是前一个 Promise 的错误,即 then 函数返回回来的 Promise 错误:
new Promise((resolve, reject) => {
throw new Error("test"); }) .then(null, (err) => { throw new Error("test1"); }) .catch((err) => console.log(err)); // Error: test1 复制代码
Promise 的错误有一种相似冒泡机制,当 catch 以前没有没有任何函数截获错误,那终究会被 catch 截获。
new Promise((resolve, reject) => {
throw new Error("test"); }) .then() .catch((err) => console.log(err)); // Error: test 复制代码
只要 catch 前任何一个 Promise 报错,那终究会被 catch 截获。 一般状况下,不建议使用 then 函数的第二个参数来进行错误的捕获,如上所说的 catch 写法能够捕获前面 then 方法执行中的错误,也更接近同步的写法(try/catch)。所以,建议老是使用 catch()方法,而不使用 then()方法的第二个参数。 then()返回一个新的 Promise 对象,catch()一样返回一个 Promise 对象,一样可使用链式调用:
new Promise((resolve, reject) => {
throw new Error("test"); }) .then() .catch((err) => console.log(err)) // Error: test .then(() => console.log(2)); // 2 复制代码
当 catch 捕获完错误后,会接着执行下面的 then 方法,当没有错误抛出时,则会跳过 catch,直接执行后面的 then 方法。可是以后的 Promise 出现错误时,以前的 catch 就捕获不到了。
new Promise((resolve, reject) => {
throw new Error("test"); }) .then() .catch((err) => { throw new Error("test1"); }) // Error: test .then(() => console.log(2)); 复制代码
catch 后面能够链式调用 then 方法,一样也能够调用 catch 方法,后面的 catch 方法是接收前一个 catch 方法所抛出的错误。
在 ES8 中新加入了一个方法,即 finally,此方法不一样于 then 和 catch,它不跟踪与 Promise 对象状态的改变,即无论 Promise 的最终状态如何,都会执行这个方法,同时 finally 不一样于 then 和 catch 地方就是,它不接受任何参数。
new Promise((resolve) => {
resolve(1); }) .then((value) => console.log(value)) // 1 .finally(() => console.log(2)); // 2 new Promise(() => { throw new Error("test"); }) .catch((err) => console.log(err)) // Error test .finally(() => console.log(2)); // 2 复制代码
finally 一样返回一个新的 Promise 对象,用法和以前的 then 和 catch 同样,这块就不作过多的讲解了。
除了上述 Promise 原型上的方法外,Promise 还有不少其余的 API。
经过字面意思就能看出来,这个方法是‘所有’意思,因而可知能够接受多个 Promise 对象。 该方法接受具备 Iterator 接口而且每一个成员都是 Promise 实例的参数,并返回一个新的 Promise 对象。
let p = Promise.all([
new Promise((resolve) => { resolve(1); }), new Promise((resolve) => { resolve(2); }), new Promise((resolve) => { resolve(3); }), ]); 复制代码
而且,只有当接受的参数中全部成员的状态都为 resolved 的时候,p 的状态才会为 resolved,若是有一个成员的状态为 rejected,那 p 的状态就为 rejected。 当全部成员的状态均为 resolved 的时候,会将每一个成员 resolved 状态下的值拼成数组传递给 p 的回调函数。
let p = Promise.all([
new Promise((resolve) => { resolve(1); }), new Promise((resolve) => { resolve(2); }), new Promise((resolve) => { resolve(3); }), ]); p.then((result) => console.log(result)); // [1, 2, 3] 复制代码
当有一个成员的状态为 rejected 的时候,则会将第一个 rejected 状态的值返给 p 的 catch 方法。
let p = Promise.all([
new Promise((resolve) => { resolve(1); }), new Promise((resolve, rejecct) => { rejecct(2); }), new Promise((resolve) => { resolve(3); }), ]); p.catch((err) => console.log(err)); 复制代码
若是有一个成员为 rejected 状态,而且自身调用了 catch 方法,那将不会走 p 对象的 catch 方法,这一点要注意。
race 翻译成中文是竞赛的意思,他表示多个 Promise 对象,哪一个成员率先改变状态,那 Promise.race 返回的 Promise 对象的状态变为何,并将值转递给 p 的回调函数,它和 Promise.all 接收的参数同样。
let p = Promise.race([
new Promise((resolve) => { setTimeout(() => resolve(1), 100); }), new Promise((resolve) => { setTimeout(() => resolve(2), 50); }), new Promise((resolve) => { setTimeout(() => resolve(3), 200); }), ]); p.then((result) => console.log(result)); // 2 let p = Promise.race([ new Promise((resolve) => { setTimeout(() => resolve(1), 100); }), new Promise((resolve, reject) => { setTimeout(() => reject(2), 50); }), new Promise((resolve) => { setTimeout(() => resolve(3), 200); }), ]); p.catch((err) => console.log(err)); // 2 复制代码
该方法是 ES2020 新加入的,和 all 同样,返回一个新的 Promise 对象,接收一组 Promise 对象,可是和 all 区别的是,当无论每一个成员的 Promise 是什么状态,只要执行结束,则返回的 Promise 对象就会执行结束。
let p = Promise.allSettled([
new Promise((resolve) => { resolve(1); }), new Promise((resolve, rejecct) => { rejecct(2); }), new Promise((resolve) => { resolve(3); }), ]); p.then((value) => console.log(JSON.stringify(value))); // [{status:"fulfilled",value:1},{status:"rejected",reason:2},{status:"fulfilled",value:3}] 复制代码
有时候异步请求并不在乎是否可以成功,这个时候这个方法就很符合场景了,而且返回一个数组,数组中每一个对象有两个状态,一个是 fulfilled,另外一个是 rejected,返回以后能够进行筛选,查看错误信息。
将一个对象转化为一个 Promise 对象。
Promise.resolve("foo");
等价于; new Promise((resolve) => resolve("foo")); 复制代码
当 Promise.resolve 的参数是一个 Promise 实例时,原封不动的返回这个实例:
let p = new Promsie((resolve) => resolve(1));
let p1 = Promise.resolve(p); p === p1; // true 复制代码
当参数是一个 thenable 对象时,即含有 then 方法的对象时,会返回一个 Promise 对象,并当即执行 then 方法。
let thenable = {
then: function (resolve, reject) { resolve(1); }, }; let p = Promise.resolve(thenable); p.then((value) => console.log(value)); // 1 复制代码
当参数是否是一个 thenable 对象时,因为参数不是一个异步的,因此当 Promise.resolve 后,直接的状态就是 resolved 的状态,因此 then 后就会输出原值。
1. 参数是个普通对象
let obj = { name: '1' } let p = Promise.resolve(obj); p.then(value=>console.log(value)) // {name: '1'} 2. 参数是个基本数据类型 let num = '1'; let p = Promise.resolve(num); p.then(value=>console.log(value)) // 1 复制代码
当不传参数的时候,返回的就是一个带有 resolved 状态的 Promise 对象。
返回一个状态为 rejected 的 Promise 对象,传入的参数做为错误信息做为后续方法传递的参数。
let num = "1";
let p = Promise.reject(num); p.then(null, (err) => console.log(err)); // 1 复制代码
当参数是 thenable 对象时,返回的不是 error 信息而是 thenable 对象。
let thenable = {
then: function (resolve, reject) { reject(1); }, }; let p = Promise.reject(thenable); p.then(null, (err) => console.log(err === thenable)); // true 复制代码
相关文章:
以为还能够的,麻烦走的时候能给点个赞,你们一块儿学习和探讨!
还能够关注个人博客但愿能给个人github上点个Start,小伙伴们必定会发现一个问题,个人全部用户名几乎都与番茄有关,由于我真的很喜欢吃番茄❤️!!!
想跟车不迷路的小伙还但愿能够关注公众号 前端老番茄 或者扫一扫下面的二维码👇👇👇。
我是一个编程界的小学生,您的鼓励是我不断前进的动力,😄但愿能一块儿加油前进。
本文使用 mdnice 排版