Promise (1) 如何使用Promise
promise 也是面试高频问题, 今天我们来看看promise是什么, 能做什么, 怎么用, 下一期我们自己来模拟一个mypromise
1 promise 是什么
我们要学会自己给自己提问, 才能加深我们的理解, 首先 promise 是一个类, 类(class)是es6 一个新的概念 ,和es5的构造函数相似,
但不完全一样,
类必须通过 new 操作符 调用 ;
子类通过super() 关键字 来产生this , 在super()之前不能使用this ;
类上有静态属性 和 静态方法 , 并且子类可以继承父类的静态属性和静态方法 ;
promise 中文 译 为 承诺 ,承诺就是说出来的话不会改变,
promise 一旦状态发生变化后就不会再变了 ,比如:
const p = new promise((resolve, reject) => { settimeout(() => { console.log(1); reject('reject'); resolve('resolve') }, 2000); }).then((data) => { console.log(data + '-suc') // 状态为 resolved 触发 }, (err) => { console.log(err + '-err') // 状态为 rejected 触发 });
结果:两秒后打印 1 , reject-err
由此可见 , 由于reject() 方法 先把 promise 的 状态 由 pendding 变为 rejected ,
所以状态就是rejected , 后面再执行resolve() 方法也没用了, 状态只改变一次。
2 promise 能做什么
promise 是为了解决异步回调地狱而出现的, 就是解决那种回调函数中嵌套回调函数的情况。。。。
它可以把这种异步操作以同步操作的流程表达出来, 一个经典的图片加载例子:
function loadimg(src) { const p = new promise((resolve, reject) => { const image = document.createelement('img'); // 创建image标签 image.src = src; // 开始加载 image.onload = () => { // 加载成功的回调 resolve(image); // 成功把image返回 }; image.onerror = () => { // 加载失败的回调 reject(new error('url not found')); // 失败丢出error } }); return p; } loadimg('https://timgsa.baidu.com/timg' + '?image&quality=80&size=b9999_10000&sec=1554215359089&di=173ff60aee0bcc177d33dced2c88b2ed' + '&imgtype=0&src=http%3a%2f%2fgss0.baidu.com%2f-fo3dsag_xi4khgko9wtanf6hhy%2fzhidao%2fpic%' + '2fitem%2f55e736d12f2eb9388d4c2ebad9628535e5dd6f50.jpg').then((data) => { document.body.appendchild(data); // 成功 把 image 标签 插入 body data.style.width = '800px'; data.style.height = '600px'; }).catch((err) => { console.log(err); // 失败打印出错误 });
效果图:
把 图片加载 和 加载成功后的数据处理函数 以 同步操作表达出来 , 而不是把数据处理函数
嵌套在图片加载成功的函数里。
3 promise 的其他注意事项
1. resolve函数 和 reject 函数 里 都可以传参 , reject里一般传error的实例,
resolve 里 除了可以传 正常的值 还可以传另一个promise实例,比如:
const p1 = new promise((resolve, reject) => { settimeout(() => { reject(new error('出错啦')) }, 4000); }); const p2 = new promise ((resolve, reject) => { settimeout(() => { resolve(p1) }, 1000); }); p2.then((data) => { console.log(data); }, (err) => { console.log(err) });
结果: 4 秒 打印出 错误信息
有的小伙伴可能会有疑问,p2 不是执行resolve函数了吗, 为什么打印出的是error 呢 ?
我们重头开始分析, p1 创建 并 立即 执行 , 4秒后 p1 执行 reject () ;
然后 p2 创建 并立即执行 , 1 秒后 执行 resolve();
1 秒钟 到了 , p2 执行 resolve(), 但是 p2 的 resolve 返回的是 p1,
那么后面 p2.then 和 p2 其实就没什么 关系 了 , 它 就和 p1 的状态 绑定 在 一起 了 ,
4 秒钟 到了 , p1 的状态 变成 rejected , p2.then 打印 error
我们再来一个 例子验证 :
const p2 = new promise ((resolve, reject) => { settimeout(() => { resolve(new promise((suc, err) => { })) }, 1000); }); p2.then((data) => { console.log(data); }, (err) => { console.log(err) });
结果 : 控制台没有任何输出
为什么 呢? p2.then 依赖 resolve()里 返回的 promise 对象 的 状态 ,
而 我 没有 调用 任何 改变 其 状态 的api , 所以 它 的状态 一直是 pendding ,
所以没有输出。
3 promise 上的静态方法
① promise.all()
它接受一个由promise对象组成的数组, 只有数组中所有promise的状态都为resolved时才会调用成功的回调,
只要有一个状态为rejected, 遇到第一个状态变为rejected时, 就会调用失败的回调;
例子:
const p1 = new promise((resolve, reject) => { settimeout(() => { resolve(1); }, 2000); }); const p2 = new promise((resolve, reject) => { resolve(2); }); const p3 = new promise((resolve, reject) => { resolve(3); }); promise.all([p1, p2, p3]).then((data) => { console.log(data); // 2 秒后输出[1, 2, 3] }).catch((error) => { console.log(error) });
两秒后所有状态才变为resolved,然后输出结果。
再看个例子:
const p1 = new promise((resolve, reject) => { settimeout(() => { resolve(1); }, 2000); }); const p2 = new promise((resolve, reject) => { reject(2); }); const p3 = new promise((resolve, reject) => { reject(3); }); promise.all([p1, p2, p3]).then((data) => { console.log(data); }).catch((error) => { console.log(error) // 2 });
p2 状态变为rejected后,promise.all()的状态就变为rejected,并打印出2,
上文我们已经说过, promise的状态只会发生一次改变, 所以即使p3状态再变为rejected,
promise.all().catch也不会再输出了。
② promise.race() 和 promise.all()相反, 只要有一个状态变为resolved, 就会执行then的回调,
并且只打印第一个状态变化返回的值
例子:
const p1 = new promise((resolve, reject) => { settimeout(() => { reject(1); },3000); }); const p2 = new promise((resolve, reject) => { settimeout(() => { reject(2); }, 1000) }); const p3 = new promise((resolve, reject) => { reject(3); }); promise.race([p1, p2, p3]).then((data) => { console.log(data + 'suc'); }).catch((error) => { console.log(error + 'err'); // 3err });
p3的状态最先发生改变所以打印3err.
promise.resolve( ) 返回一个状态为resolved的promise对象
promise.reject() 返回一个状态为rejected 的promise对象
注意事项,链式调用then() 如果不显示return, 隐式返回一个状态为resolved, 值为undefined的promise对象
例子:
const p3 = new promise((resolve, reject) => { resolve(3); }).then((data) => { console.log(data) // 3 // return promise.reject(2); }).then((data) => { console.log(data) // undefined }).then((data) => { console.log(data) // undefined });
我们再显示return
const p3 = new promise((resolve, reject) => { resolve(3); }).then((data) => { console.log(data) // 3 return promise.reject(2); }).then((data) => { console.log(data) // 不输出 }).then((data) => { console.log(data) // 不输出 }).catch((err) => { console.log('err' + err) // err2 });
catch也一样, 隐式返回一个状态为resolved, 值为undefined的promise对象,
下一期我们来研究一下promise的源码
下一篇: 盐卤有毒吗,误食盐卤怎么办
推荐阅读
-
vue中使用async、await和promise实现异步API的同步调用
-
ES6基础学习——第二天(Symbol 的基本使用、迭代器、生成器、Promise 基本语法)
-
3分钟学会Promise--API的使用(es6篇)
-
JavaScript基础教程之如何实现一个简单的promise
-
axios如何利用promise无痛刷新token的实现方法
-
JavaScript中Promise的使用详解
-
详解如何构建Promise队列实现异步函数顺序执行
-
JavaScript基础教程之如何实现一个简单的promise
-
使用Promise链式调用解决多个异步回调的问题
-
由使用request-promise-native想到的异步处理方法