1、promise介绍

  • promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
  • 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
  • 代码风格,容易理解,便于维护
  • 多个异步等待合并便于解决

    2、promise的作用?

  • 主要用于异步计算

  • 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
  • 可以在对象之间传递和操作promise,帮助我们处理队列

    3、promise主要解决了哪些问题?

  • 之前处理异步是通过纯粹的回调函数的形式进行处理

  • 很容易进入到回调地狱中,剥夺了函数return的能力
  • 问题可以解决,但是难以读懂,维护困难
  • 稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护

4、promise使用

promise有三个状态
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败

状态一经改变,不会再变,且只有两种改变方式
1、pending变为fulfilled
2、从pending变为rejected。

promise可以使用resolve和reject来改变状态
1、resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
2、reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

状态改变后,可以在.then的两个参数中接收状态改变后的值

  1. new Promise(
  2. function (resolve, reject) {
  3. // 一段耗时的异步操作
  4. resolve('成功') // 数据处理完成
  5. // reject('失败') // 数据处理出错
  6. }
  7. ).then(
  8. (res) => {console.log(res)}, // 成功
  9. (err) => {console.log(err)} // 失败
  10. )

promise还可以分多次顺序执行
在.then中的resolve本质上是新建了一个promise,因为promise状态是不可改变的。
例如分两次顺序执行

  1. new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve('hello')
  4. }, 2000)
  5. }).then(val => {
  6. console.log(val) // 参数val = 'hello'
  7. return new Promise(resolve => { //新建一个promise
  8. setTimeout(() => {
  9. resolve('world')
  10. }, 2000)
  11. })
  12. }).then(val => {
  13. console.log(val) // 参数val = 'world'
  14. })

在任何一个地方生成了一个promise队列之后,我们可以把他作为一个变量传递到其他地方。

  1. let pro = new Promise(resolve => {
  2. //此处在调用前便优先执行,等待.then调用
  3. setTimeout(() => {
  4. resolve('hello world')
  5. }, 2000)
  6. })
  7. setTimeout(() => {
  8. console.log('开始执行promise'); 此时promise
  9. pro.then(value => {
  10. console.log(value) // hello world
  11. })
  12. }, 2000)

5、错误处理

1、使用.then的第二个参数接收错误

  1. new Promise((resolve,reject) => {
  2. setTimeout(() => {
  3. // resolve('hello world')
  4. reject('error')
  5. }, 1000)
  6. }).then(value => {
  7. console.log(value) // hello world
  8. },err =>{
  9. console.log(err); //error
  10. })

2、抛出错误,使用.catch接收

  1. new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve('hello world')
  4. }, 1000)
  5. }).then(value => {
  6. console.log(value) // hello world
  7. throw new Error('test error')
  8. }).catch(err => {
  9. console.log(err);
  10. })

6、Promise.all() 批量执行

Promise.all([p1, p2, p3])用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise

  • 参数是一个数组,且数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
  • 当所有的子Promise都完成,该Promise完成,返回值是全部值的数组
  • 有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果
  1. //切菜
  2. function cutUp(){
  3. console.log('开始切菜。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('切菜完毕!');
  7. resolve('切好的菜');
  8. }, 1000);
  9. });
  10. return p;
  11. }
  12. //烧水
  13. function boil(){
  14. console.log('开始烧水。');
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('烧水完毕!');
  18. resolve('烧好的水');
  19. }, 1000);
  20. });
  21. return p;
  22. }
  23. Promise.all([cutUp(), boil()]).then((result) => {
  24. console.log('准备工作完毕');
  25. console.log(result);
  26. })
  27. //执行结果
  28. 开始切菜。
  29. 开始烧水。
  30. 切菜完毕!
  31. 烧水完毕!
  32. 准备工作完毕
  33. ['切好的菜','烧好的水']

promise.all()会等待全部完成后,所有状态改变后,如果全部为成功状态,把所有成功值返回到fulfilled;如果有失败状态,则返回首个失败状态的值到rejected

  1. //切菜
  2. function cutUp(){
  3. console.log('开始切菜。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('切菜完毕!');
  7. reject('切菜失败error');
  8. }, 2000);
  9. });
  10. return p;
  11. }
  12. //烧水
  13. function boil(){
  14. console.log('开始烧水。');
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('烧水完毕!');
  18. resolve('烧好的水');
  19. }, 1000);
  20. });
  21. return p;
  22. }
  23. Promise.all([cutUp(), boil()]).then(res => {
  24. console.log('准备工作完毕');
  25. console.log(res);
  26. },err => {
  27. console.log('准备失败');
  28. console.log(err);
  29. })
  30. //执行结果
  31. 开始切菜。
  32. 开始烧水。
  33. 烧水完毕!
  34. 切菜完毕!
  35. 准备失败
  36. 切菜失败error

7、promise.race()

Promise.race() 类似于Promise.all() ,区别在于它有任意一个完成就算完成

即promise.race()无论成功或失败状态,都会执行首个执行完成的结果到.then

  1. //切菜
  2. function cutUp(){
  3. console.log('开始切菜。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('切菜完毕!');
  7. reject('切菜失败error');
  8. }, 2000);
  9. });
  10. return p;
  11. }
  12. //烧水
  13. function boil(){
  14. console.log('开始烧水。');
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('烧水完毕!');
  18. resolve('烧好的水');
  19. }, 1000);
  20. });
  21. return p;
  22. }
  23. Promise.race([cutUp(), boil()]).then(res => {
  24. console.log('准备工作完毕');
  25. console.log(res);
  26. },err => {
  27. console.log('准备失败');
  28. console.log(err);
  29. })
  30. //执行结果
  31. 开始切菜
  32. 开始烧水
  33. 烧水完毕!
  34. 准备工作完毕
  35. 烧好的水
  36. 切菜完毕!

8、手写promise

  1. function pro(executor){
  2. let self = this
  3. self.status = 'pending'
  4. function resolve(value){
  5. if(self.status === 'pending'){ //保证状态一旦变更,不能再次修改
  6. self.status = 'resolved' //成功状态
  7. self.value = value
  8. }
  9. }
  10. function reject(reason){
  11. if(self.status === 'pending'){
  12. self.status = 'rejected' //失败状态
  13. self.reason = reason
  14. }
  15. }
  16. executor(resolve,reject) // 因为会立即执行这个执行器函数
  17. }
  18. pro.prototype.then = function(onFulfilled,onRejected){
  19. let self = this
  20. if(self.status == 'resolved'){
  21. onFulfilled(self.value)
  22. }
  23. if(self.status == 'rejected'){
  24. onRejected(self.reason)
  25. }
  26. }
  27. new pro((resolve,reject) => {
  28. console.log("a");
  29. resolve('b')
  30. reject('c')
  31. }).then(res=>{
  32. console.log(res);
  33. },err=>{
  34. console.log(err);
  35. })
  36. console.log('end');

参考文献:
https://www.jianshu.com/p/1b63a13c2701
https://juejin.cn/post/6844903779037347848#heading-1