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
都已经fulfilled
或rejected
后的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