Promise学习笔记

Promise

观感更加:https://li_ya_xu.gitee.io/xxch/pages/8657ac/

1、常见的内置错误

1.1、ReferenceError:引用的变量不存在

1 console.log(a);  // Uncaught ReferenceError: a is not defined

1.2、TypeError:数据类型不正确的错误

1 let a;
2 console.log(a.xxx); //Uncaught TypeError: Cannot read property 'xxx' of undefined

1.3、RangeError:数据值不在其所允许的范围内

1 function fn() {
2   fn()
3 }
4 fn()  //Uncaught RangeError: Maximum call stack size exceeded

1.4、SyntaxError:语法错误

1 const c = """"; //Uncaught SyntaxError: Unexpected string

2、错误的处理(捕获与抛出)

2.1、捕获错误

通过try...catch可以捕获到JS中的错误信息,错误信息包含在catch的一个对象里面,捕获错误之后,JS代码可以继续往下执行,其中的错误对象包含两个属性:

message属性:错误相关信息

stack属性:函数调用栈记录信息

1 try {
2     let d;
3     console.log(d.xxx);
4   } catch (error) {
5     console.log(error.message); //Cannot read property 'xxx' of undefined
6     console.log(error.stack); //TypeError: Cannot read property 'xxx' of undefined
7   }
8   console.log('出错之后可以继续往下执行');  //出错之后可以继续往下执行

2.2、抛出错误

通过throw new Error(),我们可以向外部抛出一个自定义的错误信息。

 1 // 抛出错误:throw error
 2   function something() {
 3     if (Date.now() % 2 === 1) {
 4       console.log('当前时间为奇数,可以执行任务');
 5     } else {  //如果时间是偶数抛出异常,由调用来处理
 6       throw new Error('当前时间为偶数无法执行任务')
 7     }
 8   }
 9 
10   // 捕获错误
11   try {
12     something() //当前时间为奇数,可以执行任务
13   } catch (error) {
14     console.log(error); //Error: 当前时间为偶数无法执行任务
15   }

3、Promise的理解与使用

3.1、promise是什么?

3.1.1、抽象表述:

Promise 是 JS 中进行异步编程的新的解决方案

3.1.2、具体表述:

(1) 从语法上来说:promise是一个构造函数

(2) 从功能上来说:promise对象用来封装一个异步操作并可以获取其结果

3.2、Promise的状态和状态的改变

3.2.1、3 种状态:

(1) 待定(pending)

(2) 兑现(fulfilled,有时候也称为“解决”,resolved)

(3) 拒绝(rejected)

3.2.2、状态改变

待定(pending)是期约的最初始状态。在待定状态下,期约可以落定(settled)为代表成功的兑现(fulfilled)状态,或者代表失败的拒绝(rejected)状态。无论落定为哪种状态都是不可逆的。只要从待定转换为兑现或拒绝,期约的状态就不再改变。而且,也不能保证期约必然会脱离待定状态。因此,组 织合理的代码无论期约解决(resolve)还是拒绝(reject),甚至永远处于待定(pending)状态,都应该具有恰当的行为。重要的是,期约的状态是私有的,不能直接通过 JavaScript 检测到。这主要是为了避免根据读取到的期约状态,以同步方式处理期约对象。另外,期约的状态也不能被外部 JavaScript 代码修改。这与不能读取该状态的原因是一样的:期约故意将异步行为封装起来,从而隔离外部的同步代码。

3.2.3、总结

pending ——> resolved

pending ——> rejected

只有这两种情况,且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为vlaue,失败的结果数据一般称为reason。

3.3、Promise的基本运行流程

3.4、promise的基本使用

 1 // 1、创建一个新的promise对象
 2 const p = new Promise((resolve, reject) => {  //执行器函数
 3   // 2、执行异步操作任务
 4   setTimeout(() => {
 5     const time = Date.now(); //如果当前时间是偶数代表成功,否则代表失败
 6     // 3、如果成功了,调用resolve(value)
 7     if (time % 2 === 0) {
 8       resolve('成功的数据,time=' + time);
 9     } else {
10       // 4、如果失败了,调用reject(reason)
11       reject('失败的数据,time=' + time);
12     }
13   }, 1000);
14 });
15 
16 p.then(
17   value => { //接收得到成功的value数据  onResolved
18     console.log('成功的回调', value);
19   },
20   reason => { //接受得到失败的reason数据  onRejected
21     console.log('失败的回调', reason);
22   }
23 )

4、Promise的API

4.1、Promise构造函数:promise(excutor){}

excutor函数:同步执行,(resolve,reject)=>{}

resolve函数:内部定义成功时我们调用的函数 value =>{}

reject函数:内部定义失败时我们调用的函数reason =>{}

说明:excutor会在promise内部立即同步回调,异步操作在执行器中执行

4.2、Promise.prototype.then方法:(onResolved,onRejected)=>{}

onResolved函数:成功的回调函数 (value)=>{}

onRejected函数:失败的回调函数 (reason)=>{}

说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象

4.3、Promise.prototype.catch方法:(onRejected)=>{}

onRejected函数:失败的回调函数 (reason)=>{}

说明:then()的语法糖,相当于hen(undefined,onRejected)

4.4、Promise.resolve方法:(value)=>{}

value:成功的数据或promise对象

说明:返回一个成功/失败的promise对象

4.5、Promise.reject方法:(reason)=>{}

reason:失败的原因

说明:返回一个失败的promise对象

4.6、Promise.all方法:(promises)=>{}

promises:包含n个promise的数组

说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败

4.7、Promise.race方法:mises)=>{}

promises:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

4.8、Promise.any()

接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。

如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,

它是 Error 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和Promise.all()是相反的。

4.9、Promise.allSettled()

​ 该Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

​ 当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个promise的结果时,通常使用它。

相比之下,Promise.all()更适合彼此相互依赖或者在其中任何一个reject时立即结束。

代码展示:

 1 new Promise((resolve, reject) => {
 2     setTimeout(() => {
 3       // resolve('成功的数据');
 4       reject('失败的数据');
 5     }, 1000);
 6   }).then(value => {
 7     console.log('onResolved1', value);
 8   }).catch(reason => {
 9     console.log('onRejected()1', reason);
10   })
11 
12   //  产生一个成功值为1的promise对象
13   const p1 = new Promise((resolve, reject) => {
14     setTimeout(() => {
15       resolve(1);
16     }, 100);
17   })
18   const p2 = Promise.resolve(2);
19   const p3 = Promise.reject(3);
20   p1.then(value => { console.log(value) })  //1
21   p2.then(value => { console.log(value) })  //2
22   p3.then(null, reason => { console.log(reason) })  //3
23   p3.catch(reason => { console.log(reason) }) //3
24 
25   // const pAll = Promise.all([p1, p2, p3]);
26   const pAll = Promise.all([p1, p2]);
27   pAll.then(
28     values => {
29       console.log('all onResolved()', values);
30     },
31     reason => {
32       console.log('all onRejected()', reason);
33     }
34   );  //all onResolved() (2) [1, 2]
35 
36   // 第一个完成的promise的结果状态就是最终的结果状态
37   const pRace = Promise.race([p1, p2, p3]);
38   pRace.then(
39     values => {
40       console.log('race onResolved()', values);
41     },
42     reason => {
43       console.log('race onRejected()', reason);
44     }
45   )   //race onResolved() 2
46 
47   const pAny = Promise.race([p1, p2, p3]);
48   pAny.then(
49     values => {
50       console.log('any onResolved()', values);
51     },
52     reason => {
53       console.log('any onRejected()', reason);
54     }
55   )   //any onResolved() 2

5、Promise的几个关键问题

5.1、如何改变promise的状态?

(1)resolve(value):如果当前是pendding就会变为resolved

(2)reject(reason):如果当前是pendding就会变为rejected

(3)抛出异常:如果当前是pendding就会变为rejected

 1 const p = new Promise((resolve, reject) => {
 2   // resolve(1)  //promise变为resolved成功状态
 3   // reject(2) //promise变为rejected失败状态
 4   // throw new Error('出错了!');  //抛出异常,promise变为rejected失败状态,reason为抛出的error
 5   throw 3   //抛出异常,promise变为rejected失败状态,reason为抛出的3
 6 });
 7 
 8 p.then(
 9   value => { },
10   reason => { console.log('reason', reason); }  //reason 3
11 )

5.2、一个promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时都会调用

 1 const p = new Promise((resolve, reject) => {
 2   // resolve(1)  //promise变为resolved成功状态
 3   // reject(2) //promise变为rejected失败状态
 4   // throw new Error('出错了!');  //抛出异常,promise变为rejected失败状态,reason为抛出的error
 5   throw 3   //抛出异常,promise变为rejected失败状态,reason为抛出的3
 6 });
 7 
 8 p.then(
 9   value => { },
10   reason => { console.log('reason', reason); }  //reason 3
11 )
12 
13 p.then(
14   value => { },
15   reason => { console.log('reason2', reason); }  //reason2 3
16 )

5.3、改变promise状态和指定回调函数谁先谁后?

(1)都有可能,正常情况下是先指定回调函数再改变状态,但也可以先改变状态再指定回调

(2)如何先改变状态再指定回调?

1、在执行器中直接调用resolve()/reject()

2、延迟更长时间才才调用then()

(3)什么时候才能得到数据?

1、如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

2、如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

 1 //常规:先指定回调函数,后改变状态
 2 new Promise((resolve, reject) => {
 3   setTimeout(() => {
 4     resolve(1); //后改变状态(同时指定数据),异步执行回调函数
 5   }, 1000);
 6 }).then(  //先指定回调函数,保存当前指定的回调函数
 7   value => { console.log('value', value); },
 8   reason => { console.log('reason', reason); }
 9 )
10 
11 //如何先改变状态再指定回调?
12 new Promise((resolve, reject) => {
13   resolve(1); //先改变状态(同时指定数据)
14 }).then(  //后指定回调函数,异步执行回调函数
15   value => { console.log('value2', value); },
16   reason => { console.log('reason2', reason); }
17 )
18 
19 const p = new Promise((resolve, reject) => {
20   setTimeout(() => {
21     resolve(1); //先改变状态(同时指定数据)
22   }, 1000);
23 });
24 
25 setTimeout(() => {
26   p.then(  //后指定回调函数,异步执行回调函数
27     value => { console.log('value3', value); },
28     reason => { console.log('reason3', reason); }
29   )
30 }, 1100);

5.4、promise.then()返回的新的promise的结果状态由什么决定?

(1)简单表述:由then()指定的回调函数执行的结果决定

(2)详细表述:

1、如果抛出异常,新promise变为rejected,reason为抛出的异常

2、如果返回的是非promise的任意值,新promise变为resolved,value为返回的值

3、如果返回的是另一个新promise,此promise的结果就会成为新promise的结果

 1 new Promise((resolve, reject) => {
 2   // resolve(1)  
 3   reject(2)
 4 }).then(
 5   value => {
 6     console.log('onResolved1()', value);
 7     // return 2;
 8     // return {a:1}
 9     // return Promise.resolve(3)
10     // return Promise.reject(4)
11     throw 5;
12   },
13   reason => {
14     console.log('onRejected1()', reason);
15     // return 2;
16     // return {a:1}
17     // return Promise.resolve(3)
18     // return Promise.reject(4)
19     throw 5;
20   }
21 ).then(
22   value => {
23     console.log('onResolved2()', value);
24   },
25   reason => {
26     console.log('onRejected2()', reason);
27   }
28 )

5.5、promise如何串联多个操作任务?

(1)promise的then()返回一个新的promise,可以看成then()的链式调用

(2)通过then的链式调用串联多个同步/异步任务,异步任务必须放到promise中。

 1 new Promise((resolve, reject) => {
 2   setTimeout(() => {
 3     console.log('执行任务1(异步)');
 4     resolve(1)
 5   }, 1000)
 6 }).then(
 7   value => {
 8     console.log('任务1的结果', value);
 9     console.log('执行任务2(同步)');
10     return 2;
11   }
12 ).then(
13   value => {
14     console.log('任务2的结果', value);
15     return new Promise((resolve, reject) => {
16       // 启动任务3(异步)
17       setTimeout(() => {
18         console.log('执行任务3(异步)');
19         resolve(3)
20       }, 1000)
21     })
22   }
23 ).then(
24   value => {
25     console.log('任务3的结果', value);
26   }
27 )
28 
29 /*
30   执行任务1(异步)
31   任务1的结果 1
32   执行任务2(同步)
33   任务2的结果 2
34   执行任务3(异步)
35   任务3的结果 3
36  */

5.6、promise异常传/穿透?

(1)当使用promise的then链式调用时,可以在最后指定失败的回调,

(2)前面任何操作出了异常,都会传到最后失败的回调中处理

 1 new Promise((resolve, reject) => {
 2     // resolve(1);
 3     reject(1)
 4   }).then(
 5     value => {
 6       console.log('onResolved1()', value);
 7       return 2;
 8     },
 9     // 没写catch,就相当于写了下面这句
10     // reason => { throw reason }
11   ).then(
12     value => {
13       console.log('onResolved2()', value);
14       return 3;
15     },
16     // 没写catch,就相当于写了下面这句
17     reason => { throw reason }
18   ).then(
19     value => {
20       console.log('onResolved3()', value);
21     },
22     // 没写catch,就相当于写了下面这句
23     // reason => { throw reason }
24     // 也可以是下面这句
25     reason => Promise.reject(reason)
26   ).catch(
27     reason => {
28       console.log('onRejected()', reason);
29     }
30   )

5.7、中断promise链?

(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数

(2)办法:在回调函数中返回一个pendding状态的promise对象

 1 new Promise((resolve, reject) => {
 2     // resolve(1);
 3     reject(1)
 4   }).then(
 5     value => {
 6       console.log('onResolved1()', value);
 7       return 2;
 8     },
 9     // 没写catch,就相当于写了下面这句
10     // reason => { throw reason }
11   ).then(
12     value => {
13       console.log('onResolved2()', value);
14       return 3;
15     },
16     // 没写catch,就相当于写了下面这句
17     reason => { throw reason }
18   ).then(
19     value => {
20       console.log('onResolved3()', value);
21     },
22     // 没写catch,就相当于写了下面这句
23     // reason => { throw reason }
24     // 也可以是下面这句
25     reason => Promise.reject(reason)
26   ).catch(
27     reason => {
28       console.log('onRejected()', reason);
29       // 返回下面两句,进入失败的回调
30       // throw reason;
31       // return Promise.reject(reason)
32       return new Promise(() => { }) //返回一个pendding的promise,中断promise链
33     }
34   ).then(
35     value => {
36       console.log('onResolved4()', value);
37     },
38     reason => {
39       console.log('onRejected2()', reason);
40     }
41   )

6、自定义(手写)Promise

6.1、定义整体结构

新建文件lib/promise,存放我们自定义的Promise

 1 /* 
 2 自定义Promise函数模块:IIFE
 3 */
 4 (function (window) {
 5   /* 
 6   Promise构造函数
 7   excutor: 执行器函数(同步执行)
 8   */
 9   function Promise() {}
10 
11   /* 
12   Promise原型对象的then()
13   指定成功和失败的回调函数
14   返回一个新的promise对象
15   */
16   Promise.prototype.then = function (onResolved, onRejected) {}
17 
18   /* 
19   Promise原型对象的catch()
20   指定失败的回调函数
21   返回一个新的promise对象
22   */
23   Promise.prototype.catch = function (onRejected) {}
24 
25   /* 
26   Promise函数对象的resolve方法
27   返回一个指定结果的成功的promise
28   */
29   Promise.resolve = function (value) {}
30 
31   /* 
32   Promise函数对象的reject方法
33   返回一个指定的reason的失败的promise
34   */
35   Promise.reject = function (reason) {}
36 
37   /* 
38   Promise函数对象的all方法
39   返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
40   */
41   Promise.all = function (promises) {}
42 
43   /* 
44   Promise函数对象的race方法
45   返回一个promise,其结果由第一个完成的promise决定
46   */
47   Promise.race = function (promises) {}
48 
49   // 向外暴露Promise函数
50   window.Promise = Promise;
51 })(window)

6.2、实现Promise构造函数

先简单实现

 1 /* 
 2   Promise构造函数
 3   excutor: 执行器函数(同步执行)
 4   */
 5   function Promise(excutor) {
 6     // 将当前promise对象保存起来
 7     const self = this;
 8     // 给promise对象指定status属性,初始值为pendding
 9     self.status = 'pending';
10     // 给promise对象指定一个用于存储结果数据的属性
11     self.data = undefined;
12     // 每个元素的结构:{ onResolved(){}, onRejected(){} }
13     self.callbacks = [];
14 
15     function resolve(value) {
16       // 如果当前状态不是pending,直接结束
17       if (self.status !== 'pending') {
18         return
19       }
20 
21       // 将状态改为resolved
22       self.status = 'resolved';
23       // 保存value数据
24       self.data = value;
25       // 如果有待执行callback函数,立即异步执行回调函数onResolved
26       if (self.callbacks.length > 0) {
27         setTimeout(() => { //放入队列中执行所有成功的回调
28           self.callbacks.forEach(calbacksObj => {
29             calbacksObj.onResolved(value)
30           });
31         });
32       }
33     }
34 
35     function reject(reason) {
36       // 如果当前状态不是pending,直接结束
37       if (self.status !== 'pending') {
38         return
39       }
40 
41       // 将状态改为rejected
42       self.status = 'rejected';
43       // 保存value数据
44       self.data = reason;
45       // 如果有待执行callback函数,立即异步执行回调函数onRejected
46       if (self.callbacks.length > 0) {
47         setTimeout(() => { //放入队列中执行所有成功的回调
48           self.callbacks.forEach(calbacksObj => {
49             calbacksObj.onRejected(reason)
50           });
51         });
52       }
53     }
54 
55     // 立即同步执行excutor
56     try {
57       excutor(resolve, reject)
58     } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
59       reject(error)
60     }
61   }

6.3、Promise.then方法的实现

 1 /* 
 2   Promise原型对象的then()
 3   指定成功和失败的回调函数
 4   返回一个新的promise对象
 5   返回promise的结果由onResolved/onRejected执行结果决定
 6   */
 7   Promise.prototype.then = function (onResolved, onRejected) {
 8     // 向后传递成功的value
 9     onResolved = typeof onResolved === 'function' ? onResolved : value => value
10     // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
11     onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
12       throw reason
13     }
14     const self = this;
15 
16     // 返回一个新的promise
17     return new Promise((resolve, reject) => {
18 
19       /* 
20       调用指定的回调函数处理,根据执行结果,改变return的promise的状态
21       */
22       function handle(callback) {
23         /* 
24         1、如果抛出异常,return的promise就会失败,reason就是error
25         2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
26         3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
27         */
28         try {
29           const result = callback(self.data);
30           // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
31           if (result instanceof Promise) {
32             // result.then(
33             //   value => resolve(value), // 当result成功时,让return的promise也成功
34             //   reason => reject(reason) // 当result失败时,让return的promise也失败
35             // )
36             // 简写
37             result.then(resolve, reject)
38           } else {
39             // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
40             resolve(result)
41           }
42         } catch (error) {
43           // 1、如果抛出异常,return的promise就会失败,reason就是error
44           reject(error)
45         }
46       }
47 
48       if (self.status === PENDING) {
49         // 当前状态还是pending状态,将回调函数保存起来
50         self.callbacks.push({
51           onResolved(value) {
52             handle(onResolved)
53           },
54           onRejected(reason) {
55             handle(onRejected)
56           }
57         })
58       } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
59         setTimeout(() => {
60           handle(onResolved)
61         });
62       } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
63         setTimeout(() => {
64           handle(onRejected)
65         });
66       }
67     })
68 
69   }

6.4、Promise.catch方法的实现

1 /* 
2   Promise原型对象的catch()
3   指定失败的回调函数
4   返回一个新的promise对象
5   */
6   Promise.prototype.catch = function (onRejected) {
7     return this.then(undefined, onRejected)
8   }

6.5、Promise.resolve()/reject()方法的实现

 1 /* 
 2   Promise函数对象的resolve方法
 3   返回一个指定结果的成功的promise
 4   */
 5   Promise.resolve = function (value) {
 6     // 返回一个成功/失败的promise
 7     return new Promise((resolve, reject) => {
 8       // value 是promise
 9       if (value instanceof Promise) { // 使用value的结果作为promise的结果
10         value.then(resolve, reject);
11       } else { // value 不是promise => promise变为成功,数据是value
12         resolve(value);
13       }
14     })
15   }
16 
17   /* 
18   Promise函数对象的reject方法
19   返回一个指定的reason的失败的promise
20   */
21   Promise.reject = function (reason) {
22     // 返回一个失败的promise
23     return new Promise((resolve, reject) => {
24       reject(reason)
25     })
26   }

6.6、Promise.all()方法的实现

 1 /* 
 2   Promise函数对象的all方法
 3   返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
 4   */
 5   Promise.all = function (promises) {
 6     // 用来保存所有成功value的数组
 7     const values = new Array(promises.length);
 8     // 用来保存成功promise的数量
 9     let resolvedCount = 0;
10     // 返回一个新的promise
11     return new Promise((resolve, reject) => {
12       // 遍历promises获取每个promise的结果
13       promises.forEach((p, index) => {
14         Promise.resolve(p).then(
15           value => {
16             resolvedCount++ //成功的数量加1
17             // p成功,将成功的value保存到values
18             values[index] = value
19             // 如果全部成功了,将return的promise改变成功
20             if (resolvedCount === promises.length) {
21               resolve(values)
22             }
23           },
24           reason => { // 只要一个失败了,return的promise就失败
25             reject(reason)
26           }
27         )
28       })
29     })
30   }

6.7、Promise.race()方法的实现

 1 /* 
 2   Promise函数对象的race方法
 3   返回一个promise,其结果由第一个完成的promise决定
 4   */
 5   Promise.race = function (promises) {
 6     // 返回一个新的promise
 7     return new Promise((resolve, reject) => {
 8       // 遍历promises获取每个promise的结果
 9       promises.forEach((p, index) => {
10         Promise.resolve(p).then(
11           value => { // 一旦有成功了,将return变为成功
12             resolve(value)
13           },
14           reason => { // 一旦有失败了,将return变为失败
15             reject(reason)
16           }
17         )
18       })
19     })
20   }

6.8、自定义Promise.resolveDelay()方法

 1 /* 
 2   返回一个promise对象,它在指定的时间之后才确定结果
 3   */
 4   Promise.resolveDelay = function (value, time) {
 5     // 返回一个成功/失败的promise
 6     return new Promise((resolve, reject) => {
 7       setTimeout(() => {
 8         // value 是promise
 9         if (value instanceof Promise) { // 使用value的结果作为promise的结果
10           value.then(resolve, reject);
11         } else { // value 不是promise => promise变为成功,数据是value
12           resolve(value);
13         }
14       }, time);
15     })
16   }

6.9、自定义Promise.rejectDelay()方法

 1 /* 
 2   返回一个promise对象,它在指定的时间之后才失败
 3   */
 4   Promise.rejectDelay = function (reason, time) {
 5     // 返回一个失败的promise
 6     return new Promise((resolve, reject) => {
 7       setTimeout(() => {
 8         reject(reason)
 9       }, time);
10     })
11   }

6.10、手写Promise完整版

  1 /* 
  2 自定义Promise函数模块:IIFE
  3 */
  4 (function (window) {
  5 
  6   const PENDING = 'pending';
  7   const RESOLVED = 'resolved';
  8   const REJECTED = 'rejected';
  9 
 10   /* 
 11   Promise构造函数
 12   excutor: 执行器函数(同步执行)
 13   */
 14   function Promise(excutor) {
 15     // 将当前promise对象保存起来
 16     const self = this;
 17     // 给promise对象指定status属性,初始值为pendding
 18     self.status = PENDING;
 19     // 给promise对象指定一个用于存储结果数据的属性
 20     self.data = undefined;
 21     // 每个元素的结构:{ onResolved(){}, onRejected(){} }
 22     self.callbacks = [];
 23 
 24     function resolve(value) {
 25       // 如果当前状态不是pending,直接结束
 26       if (self.status !== PENDING) {
 27         return
 28       }
 29 
 30       // 将状态改为resolved
 31       self.status = RESOLVED;
 32       // 保存value数据
 33       self.data = value;
 34       // 如果有待执行callback函数,立即异步执行回调函数onResolved
 35       if (self.callbacks.length > 0) {
 36         setTimeout(() => { //放入队列中执行所有成功的回调
 37           self.callbacks.forEach(calbacksObj => {
 38             calbacksObj.onResolved(value)
 39           });
 40         });
 41       }
 42     }
 43 
 44     function reject(reason) {
 45       // 如果当前状态不是pending,直接结束
 46       if (self.status !== PENDING) {
 47         return
 48       }
 49 
 50       // 将状态改为rejected
 51       self.status = REJECTED;
 52       // 保存value数据
 53       self.data = reason;
 54       // 如果有待执行callback函数,立即异步执行回调函数onRejected
 55       if (self.callbacks.length > 0) {
 56         setTimeout(() => { //放入队列中执行所有成功的回调
 57           self.callbacks.forEach(calbacksObj => {
 58             calbacksObj.onRejected(reason)
 59           });
 60         });
 61       }
 62     }
 63 
 64     // 立即同步执行excutor
 65     try {
 66       excutor(resolve, reject)
 67     } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
 68       reject(error)
 69     }
 70   }
 71 
 72   /* 
 73   Promise原型对象的then()
 74   指定成功和失败的回调函数
 75   返回一个新的promise对象
 76   返回promise的结果由onResolved/onRejected执行结果决定
 77   */
 78   Promise.prototype.then = function (onResolved, onRejected) {
 79     // 向后传递成功的value
 80     onResolved = typeof onResolved === 'function' ? onResolved : value => value
 81     // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
 82     onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
 83       throw reason
 84     }
 85     const self = this;
 86 
 87     // 返回一个新的promise
 88     return new Promise((resolve, reject) => {
 89 
 90       /* 
 91       调用指定的回调函数处理,根据执行结果,改变return的promise的状态
 92       */
 93       function handle(callback) {
 94         /* 
 95         1、如果抛出异常,return的promise就会失败,reason就是error
 96         2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
 97         3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
 98         */
 99         try {
100           const result = callback(self.data);
101           // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
102           if (result instanceof Promise) {
103             // result.then(
104             //   value => resolve(value), // 当result成功时,让return的promise也成功
105             //   reason => reject(reason) // 当result失败时,让return的promise也失败
106             // )
107             // 简写
108             result.then(resolve, reject)
109           } else {
110             // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
111             resolve(result)
112           }
113         } catch (error) {
114           // 1、如果抛出异常,return的promise就会失败,reason就是error
115           reject(error)
116         }
117       }
118 
119       if (self.status === PENDING) {
120         // 当前状态还是pending状态,将回调函数保存起来
121         self.callbacks.push({
122           onResolved(value) {
123             handle(onResolved)
124           },
125           onRejected(reason) {
126             handle(onRejected)
127           }
128         })
129       } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
130         setTimeout(() => {
131           handle(onResolved)
132         });
133       } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
134         setTimeout(() => {
135           handle(onRejected)
136         });
137       }
138     })
139 
140   }
141 
142   /* 
143   Promise原型对象的catch()
144   指定失败的回调函数
145   返回一个新的promise对象
146   */
147   Promise.prototype.catch = function (onRejected) {
148     return this.then(undefined, onRejected)
149   }
150 
151   /* 
152   Promise函数对象的resolve方法
153   返回一个指定结果的成功的promise
154   */
155   Promise.resolve = function (value) {
156     // 返回一个成功/失败的promise
157     return new Promise((resolve, reject) => {
158       // value 是promise
159       if (value instanceof Promise) { // 使用value的结果作为promise的结果
160         value.then(resolve, reject);
161       } else { // value 不是promise => promise变为成功,数据是value
162         resolve(value);
163       }
164     })
165   }
166 
167   /* 
168   Promise函数对象的reject方法
169   返回一个指定的reason的失败的promise
170   */
171   Promise.reject = function (reason) {
172     // 返回一个失败的promise
173     return new Promise((resolve, reject) => {
174       reject(reason)
175     })
176   }
177 
178   /* 
179   Promise函数对象的all方法
180   返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
181   */
182   Promise.all = function (promises) {
183     // 用来保存所有成功value的数组
184     const values = new Array(promises.length);
185     // 用来保存成功promise的数量
186     let resolvedCount = 0;
187     // 返回一个新的promise
188     return new Promise((resolve, reject) => {
189       // 遍历promises获取每个promise的结果
190       promises.forEach((p, index) => {
191         Promise.resolve(p).then(
192           value => {
193             resolvedCount++ //成功的数量加1
194             // p成功,将成功的value保存到values
195             values[index] = value
196             // 如果全部成功了,将return的promise改变成功
197             if (resolvedCount === promises.length) {
198               resolve(values)
199             }
200           },
201           reason => { // 只要一个失败了,return的promise就失败
202             reject(reason)
203           }
204         )
205       })
206     })
207   }
208 
209   /* 
210   Promise函数对象的race方法
211   返回一个promise,其结果由第一个完成的promise决定
212   */
213   Promise.race = function (promises) {
214     // 返回一个新的promise
215     return new Promise((resolve, reject) => {
216       // 遍历promises获取每个promise的结果
217       promises.forEach((p, index) => {
218         Promise.resolve(p).then(
219           value => { // 一旦有成功了,将return变为成功
220             resolve(value)
221           },
222           reason => { // 一旦有失败了,将return变为失败
223             reject(reason)
224           }
225         )
226       })
227     })
228   }
229 
230   /* 
231   返回一个promise对象,它在指定的时间之后才确定结果
232   */
233   Promise.resolveDelay = function (value, time) {
234     // 返回一个成功/失败的promise
235     return new Promise((resolve, reject) => {
236       setTimeout(() => {
237         // value 是promise
238         if (value instanceof Promise) { // 使用value的结果作为promise的结果
239           value.then(resolve, reject);
240         } else { // value 不是promise => promise变为成功,数据是value
241           resolve(value);
242         }
243       }, time);
244     })
245   }
246 
247   /* 
248   返回一个promise对象,它在指定的时间之后才失败
249   */
250   Promise.rejectDelay = function (reason, time) {
251     // 返回一个失败的promise
252     return new Promise((resolve, reject) => {
253       setTimeout(() => {
254         reject(reason)
255       }, time);
256     })
257   }
258   
259   // 向外暴露Promise函数
260   window.Promise = Promise;
261 })(window)

7、自定义(手写)Promise之class版

  1 /* 
  2 自定义Promise函数模块:IIFE
  3 */
  4 (function (window) {
  5 
  6   const PENDING = 'pending';
  7   const RESOLVED = 'resolved';
  8   const REJECTED = 'rejected';
  9 
 10   class Promise {
 11     /* 
 12   Promise构造函数
 13   excutor: 执行器函数(同步执行)
 14   */
 15     constructor(excutor) {
 16       // 将当前promise对象保存起来
 17       const self = this;
 18       // 给promise对象指定status属性,初始值为pendding
 19       self.status = PENDING;
 20       // 给promise对象指定一个用于存储结果数据的属性
 21       self.data = undefined;
 22       // 每个元素的结构:{ onResolved(){}, onRejected(){} }
 23       self.callbacks = [];
 24 
 25       function resolve(value) {
 26         // 如果当前状态不是pending,直接结束
 27         if (self.status !== PENDING) {
 28           return
 29         }
 30 
 31         // 将状态改为resolved
 32         self.status = RESOLVED;
 33         // 保存value数据
 34         self.data = value;
 35         // 如果有待执行callback函数,立即异步执行回调函数onResolved
 36         if (self.callbacks.length > 0) {
 37           setTimeout(() => { //放入队列中执行所有成功的回调
 38             self.callbacks.forEach(calbacksObj => {
 39               calbacksObj.onResolved(value)
 40             });
 41           });
 42         }
 43       }
 44 
 45       function reject(reason) {
 46         // 如果当前状态不是pending,直接结束
 47         if (self.status !== PENDING) {
 48           return
 49         }
 50 
 51         // 将状态改为rejected
 52         self.status = REJECTED;
 53         // 保存value数据
 54         self.data = reason;
 55         // 如果有待执行callback函数,立即异步执行回调函数onRejected
 56         if (self.callbacks.length > 0) {
 57           setTimeout(() => { //放入队列中执行所有成功的回调
 58             self.callbacks.forEach(calbacksObj => {
 59               calbacksObj.onRejected(reason)
 60             });
 61           });
 62         }
 63       }
 64 
 65       // 立即同步执行excutor
 66       try {
 67         excutor(resolve, reject)
 68       } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
 69         reject(error)
 70       }
 71     }
 72 
 73     /* 
 74   Promise原型对象的then()
 75   指定成功和失败的回调函数
 76   返回一个新的promise对象
 77   返回promise的结果由onResolved/onRejected执行结果决定
 78   */
 79     then(onResolved, onRejected) {
 80       // 向后传递成功的value
 81       onResolved = typeof onResolved === 'function' ? onResolved : value => value
 82       // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
 83       onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
 84         throw reason
 85       }
 86       const self = this;
 87 
 88       // 返回一个新的promise
 89       return new Promise((resolve, reject) => {
 90 
 91         /* 
 92         调用指定的回调函数处理,根据执行结果,改变return的promise的状态
 93         */
 94         function handle(callback) {
 95           /* 
 96           1、如果抛出异常,return的promise就会失败,reason就是error
 97           2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
 98           3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
 99           */
100           try {
101             const result = callback(self.data);
102             // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
103             if (result instanceof Promise) {
104               // result.then(
105               //   value => resolve(value), // 当result成功时,让return的promise也成功
106               //   reason => reject(reason) // 当result失败时,让return的promise也失败
107               // )
108               // 简写
109               result.then(resolve, reject)
110             } else {
111               // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
112               resolve(result)
113             }
114           } catch (error) {
115             // 1、如果抛出异常,return的promise就会失败,reason就是error
116             reject(error)
117           }
118         }
119 
120         if (self.status === PENDING) {
121           // 当前状态还是pending状态,将回调函数保存起来
122           self.callbacks.push({
123             onResolved(value) {
124               handle(onResolved)
125             },
126             onRejected(reason) {
127               handle(onRejected)
128             }
129           })
130         } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
131           setTimeout(() => {
132             handle(onResolved)
133           });
134         } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
135           setTimeout(() => {
136             handle(onRejected)
137           });
138         }
139       })
140 
141     }
142 
143     /* 
144     Promise原型对象的catch()
145     指定失败的回调函数
146     返回一个新的promise对象
147     */
148     catch (onRejected) {
149       return this.then(undefined, onRejected)
150     }
151 
152     /* 
153     Promise函数对象的resolve方法
154     返回一个指定结果的成功的promise
155     */
156     static resolve = function (value) {
157       // 返回一个成功/失败的promise
158       return new Promise((resolve, reject) => {
159         // value 是promise
160         if (value instanceof Promise) { // 使用value的结果作为promise的结果
161           value.then(resolve, reject);
162         } else { // value 不是promise => promise变为成功,数据是value
163           resolve(value);
164         }
165       })
166     }
167 
168     /* 
169     Promise函数对象的reject方法
170     返回一个指定的reason的失败的promise
171     */
172     static reject = function (reason) {
173       // 返回一个失败的promise
174       return new Promise((resolve, reject) => {
175         reject(reason)
176       })
177     }
178 
179     /* 
180     Promise函数对象的all方法
181     返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
182     */
183     static all = function (promises) {
184       // 用来保存所有成功value的数组
185       const values = new Array(promises.length);
186       // 用来保存成功promise的数量
187       let resolvedCount = 0;
188       // 返回一个新的promise
189       return new Promise((resolve, reject) => {
190         // 遍历promises获取每个promise的结果
191         promises.forEach((p, index) => {
192           Promise.resolve(p).then(
193             value => {
194               resolvedCount++ //成功的数量加1
195               // p成功,将成功的value保存到values
196               values[index] = value
197               // 如果全部成功了,将return的promise改变成功
198               if (resolvedCount === promises.length) {
199                 resolve(values)
200               }
201             },
202             reason => { // 只要一个失败了,return的promise就失败
203               reject(reason)
204             }
205           )
206         })
207       })
208     }
209 
210     /* 
211     Promise函数对象的race方法
212     返回一个promise,其结果由第一个完成的promise决定
213     */
214     static race = function (promises) {
215       // 返回一个新的promise
216       return new Promise((resolve, reject) => {
217         // 遍历promises获取每个promise的结果
218         promises.forEach((p, index) => {
219           Promise.resolve(p).then(
220             value => { // 一旦有成功了,将return变为成功
221               resolve(value)
222             },
223             reason => { // 一旦有失败了,将return变为失败
224               reject(reason)
225             }
226           )
227         })
228       })
229     }
230 
231     /* 
232     返回一个promise对象,它在指定的时间之后才确定结果
233     */
234     static resolveDelay = function (value, time) {
235       // 返回一个成功/失败的promise
236       return new Promise((resolve, reject) => {
237         setTimeout(() => {
238           // value 是promise
239           if (value instanceof Promise) { // 使用value的结果作为promise的结果
240             value.then(resolve, reject);
241           } else { // value 不是promise => promise变为成功,数据是value
242             resolve(value);
243           }
244         }, time);
245       })
246     }
247 
248     /* 
249     返回一个promise对象,它在指定的时间之后才失败
250     */
251     static rejectDelay = function (reason, time) {
252       // 返回一个失败的promise
253       return new Promise((resolve, reject) => {
254         setTimeout(() => {
255           reject(reason)
256         }, time);
257       })
258     }
259   }
260 
261   // 向外暴露Promise函数
262   window.Promise = Promise;
263 })(window)

8、async函数

函数的返回值为promise对象

promise对象的结果由async函数执行的返回值决定

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

 1 // async函数的返回值是一个promise对象
 2   // async函数返回的promise的结果由函数执行的结果决定
 3   async function fn1() {
 4     // return 1
 5     // throw 2
 6     // return Promise.reject(3);
 7     // return Promise.resolve(4);
 8     return new Promise((resolve, reject) => {
 9       setTimeout(() => {
10         resolve(5)
11       }, 1000);
12     })
13   }
14   const result = fn1()
15   // console.log(result);
16   result.then(
17     value => {
18       console.log('onResolved()', value);
19     },
20     reason => {
21       console.log('onRejected()', reason);
22     }
23   )

9、await

1、await 表达式

await右侧的表达式一般为promise对象,但也可以是其他的值

如果是promise对象,await返回的是promise成功的值

如果表达式是其他值,直接将此值作为await的返回值

2、注意:

await必须写在async函数中,但async函数中可以没有await

如果await的promise失败了,就会抛出异常,需要通过try...catch来捕获处理

3、参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

 1 function fn2() {
 2     return new Promise((resolve, reject) => {
 3       setTimeout(() => {
 4         // resolve(6)
 5         reject(6)
 6       }, 1000);
 7     })
 8   }
 9 
10   function fn4() {
11     return 7
12   }
13 
14   async function fn3() {
15     try {
16       const value = await fn2(); // await右侧表达式为promise,得到的结果就是promise对象的处理结果
17     } catch (error) {
18       console.log('得到失败的结果', error);
19     }
20 
21     // const value = await fn4() // await右侧表达式不是promise,得到的结果就是它本身
22     // console.log('value', value);
23   }
24   fn3()

10、JS异步之宏队列与微队列

JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队

宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM 事件回调 /ajax 回调

微 列 队 : 用 来 保 存 待 执 行 的 微 任 务 ( 回 调 ), 比 如 : promise 的 回 调 /MutationObserver 的回调

JS 执行时会区别这 2 个队列

(1) JS 引擎首先必须先执行所有的初始化同步任务代码

(2) 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行

 1 setTimeout(() => {  // 会立即放入宏队列
 2     console.log('timeout callback1()');
 3   }, 0);
 4   
 5   setTimeout(() => {  // 会立即放入宏队列
 6     console.log('timeout callback2()');
 7   }, 0);
 8 
 9   Promise.resolve(1).then(
10     value => {  // 会立即放入微队列
11       console.log('Promise onResolved1()', value);
12     }
13   )
14   Promise.resolve(2).then(
15     value => {  // 会立即放入微队列
16       console.log('Promise onResolved2()', value);
17     }
18   )

11、相关面试题

 1 setTimeout(() => {
 2     console.log(1);
 3   }, 0);
 4 
 5   Promise.resolve().then(() => {
 6     console.log(2);
 7   })
 8 
 9   Promise.resolve().then(() => {
10     console.log(4);
11   })
12 
13   console.log(3);
14 
15   // 3、2、4、1
 1 setTimeout(() => {
 2     console.log(1);
 3   }, 0);
 4 
 5   new Promise((resolve) => {
 6     console.log(2);
 7     resolve()
 8   }).then(
 9     () => { console.log(3) }
10   ).then(
11     () => { console.log(4) }
12   )
13   console.log(5);
14 
15   // 2、5、3、4、1
 1 const first = () => (new Promise((resolve, reject) => {
 2     console.log(3)
 3     let p = new Promise((resolve, reject) => {
 4       console.log(7)
 5       setTimeout(() => {
 6         console.log(5)
 7         resolve(6)
 8       }, 0)
 9       resolve(1)
10     })
11     resolve(2)
12     p.then((arg) => {
13       console.log(arg)
14     })
15   }))
16   first().then((arg) => {
17     console.log(arg)
18   })
19   console.log(4)
20 
21   // 3、7、4、1、2、5
 1 setTimeout(() => {
 2     console.log("0")
 3   }, 0)
 4   new Promise((resolve, reject) => {
 5     console.log("1")
 6     resolve()
 7   }).then(() => {
 8     console.log("2")
 9     new Promise((resolve, reject) => {
10       console.log("3")
11       resolve()
12     }).then(() => {
13       console.log("4")
14     }).then(() => {
15       console.log("5")
16     })
17   }).then(() => {
18     console.log("6")
19   })
20   new Promise((resolve, reject) => {
21     console.log("7")
22     resolve()
23   }).then(() => {
24     console.log("8")
25   })
26 
27   // 1、7、2、3、8、4、6、5、0
posted @ 2020-12-03 15:25  小笑残虹  阅读(147)  评论(0编辑  收藏  举报