期约是一种机制。
期约通常表示一个正在处理的、尚未结束的操作,当相关操作结束时,期约会通知系统。
期约机制是 ECMAScript 实现异步编程的重要组成部分。
目前,流行的期约机制的规范是规范 Promises/A+ 。
ES6 规范以规范 Promises/A+ 为范本,来实现期约。
ES6 新增类型 Promise ,来实现(支持)规范 Promises/A+ 。
主要参考资料:
- 《JavaScript 高级程序设计(第4版)》- P325(350/931)
期约状态机
期约主要有两个内部属性:
- 期约的状态
- 期约的值
期约的状态
期约有三种状态:
- 待定(pending)
- 兑现 / 履行(fulfilled)(也称作:解决(resolved))
- 拒绝(rejected)
期约的状态代表期约是否完成:
- 待定,表示期约尚未开始或者正在执行。
- 解决,表示期约已成功完成。
- 拒绝,表示期约没有成功完成。
期约的状态切换
期约的待定状态,被称为初始状态。
期约的解决状态、拒绝状态,被称为落定(settled)状态。
期约的状态可以从初始状态切换到落定状态,即:
- 期约从待定状态切换到解决状态。
- 期约从待定状态切换到拒绝状态。
期约从初始状态切换到落定状态的过程被称为落定。
期约的落定是不可逆的,只要期约切换到落定状态,期约的状态就不会再发生改变。
期约的值
当期约转换为落定状态时,期约内部会生成一个值:
- 当期约落定为解决时,这个值被简单地称为解决期约的值(value)。
- 当期约落定为拒绝时,这个值被称为拒绝期约的理由(reason)。
期约的值的默认值为 undefined 。
创建期约实例
通过类型 Promise 的构造函数 Promise() ,创建期约实例。
期约的构造函数 Promise() :
-
接收一个参数:
函数,期约的执行函数,提供两个参数:-
resolve ,函数,使期约实例的状态落定为解决。
接收一个参数(可选):任意值,作为解决期约实例的值。 -
reject ,函数,使期约实例的状态落定为拒绝。
接收一个参数(可选):任意值,作为拒绝期约实例的理由。
-
-
返回值:
期约。
关于执行函数:
在调用函数 resolve() 、reject() 之前,期约实例一直处于初始状态。
调用 resolve() 、reject() 中的任意一个,期约实例从初始状态切换为相应的落定状态。
期约实例处于落定状态后,再次调用 resolve() 、reject() 会静默失败,即期约实例落定后,不能改变期约实例的状态。
在执行函数中抛出错误,会导致构造函数 Promise() 返回一个拒绝期约,拒绝的理由为抛出的错误。
示例:
-
创建一个待定期约实例
const promise = new Promise( () => { console.log('Create a promise') } ) console.log(promise) // 输出: // Create a promise // Promise {<pending>} -
创建一个期约实例,1s 后期约实例落定为解决期约
const promise_01 = new Promise( (resolve) => { setTimeout( () => { console.log(promise_01) resolve() // 落定为解决期约 }, 1000 ) } ) // 输出: // Promise {<fulfilled>: undefined} -
创建一个期约实例,1s 后期约实例落定为拒绝期约
const promise_02 = new Promise( (_, reject) => { setTimeout( () => { reject() // 落定为拒绝期约 console.log(promise_02) }, 1000 ) } ) // 输出: // Promise {<rejected>: undefined} -
创建一个期约实例,1s 后期约实例随机落定,并指定落定期约的内部值。
const promise_03 = new Promise( (resolve, reject) => { // 定义函数,对期约实例进行随机落定 function randomSettle() { /** * Math.random() ,返回区间为 [0, 1) 的随机数 * Math.round(x) ,对 x 进行四舍五入,并返回结果 */ const handle = Math.round(Math.random()) switch(handle) { case 0: resolve('is resolved') // 落定为解决期约,并指定解决期约的值 break case 1: reject('is rejected') // 落定为拒绝期约,并指定拒绝期约的理由 break default: break } } setTimeout( () => { randomSettle() console.log(promise_03) }, 1000 ) } ) // 可能的输出_01: // Promise {<fulfilled>: is resolved} // 可能的输出_02: // Promise {<rejected>: is rejected}
创建解决期约实例
通过期约的静态函数 Promise.resolve() ,创建解决期约实例。
期约的静态函数 Promise.resolve() :
-
功能:
创建一个解决期约实例。 -
接收一个参数(可选):
任意值,作为解决期约实例的值。 -
返回值:
对象,解决期约实例。
示例:
- 创建一个解决期约实例,并指定解决期约的值。
const promise = Promise.resolve('is resolved') console.log(promise) // 输出: // Promise {<fulfilled>: 'is resolved'}
如果给静态函数 Promise.resolve() 传入的参数是一个期约,那么静态函数 Promise.resolve() 返回的是该期约自身。
示例:
- 给静态函数 Promise.resolve() 传入一个期约。
const promise = Promise.resolve('is resolved') const nestedPromise = Promise.resolve(promise) console.log(promise === nestedPromise) // 输出: // true
创建拒绝期约实例
通过期约的静态函数 Promise.reject() ,创建拒绝期约实例。
期约的静态函数 Promise.reject() :
-
功能:
创建一个拒绝期约实例。 -
接收一个参数(可选):
任意值,作为拒绝期约实例的理由。 -
返回值:
对象,拒绝期约实例。
示例:
- 创建一个拒绝期约实例,并指定拒绝期约的理由。
const promise = Promise.reject('is rejected') console.log(promise) // 输出: // Promise {<rejected>: 'is rejected'}
期约的落定
开发者只能在期约的执行函数中落定期约。
ES6 没有向开发者提供更多其它的可以动态改变期约状态的 API 。
期约状态的变化主要由 JavaScript 引擎根据 ES6 的期约规范进行控制。
ES6 没有向开发者提供可以获取期约状态的 API
期约状态只能通过函数 console.log() 打印出来。
即开发者不能通过原生 API 将期约的状态作为判断条件来进行开发,说明期约规范本身不建议(允许)开发者这样使用期约。
响应期约的落定
通过期约的原型方法 then() 、catch()、finally() ,向期约实例添加处理程序,可以响应期约实例的落定。
期约的原型方法 then() 、catch()、finally() 都会排期任务,即向消息队列添加任务。
所以通过期约的原型方法 then()、catch()、fianlly() 添加的处理程序,都会被排期到消息队列中,被异步执行。
前置知识
关于期约:
ES6 的期约实现了接口 Thenable 。
接口 Thenable :
- 拥有一个方法:
then(callback) ,用于指定后续执行的程序。
示例:- 实现接口 Thenable 的对象。
const obj = { then(callback) { // ... callback('param') // ... } }
关于拒绝期约:
如果期约落定为拒绝期约,拒绝期约会抛出一个异步错误,异步错误的值为拒绝期约的理由。
拒绝期约抛出的异步错误,只能由该拒绝期约的拒绝处理程序捕获并处理。
Promise.prototype.then()
期约的原型方法 then() 用于为期约实例添加异步执行的解决处理程序、拒绝处理程序。
期约的原型方法 then() 会排期一个任务。
期约的原型方法 Promise.prototype.then() :
-
功能:
为期约实例添加异步执行的解决处理程序、拒绝处理程序。 -
接收两个参数:
-
函数(可选)
onResolved 处理程序(解决处理程序) ,在当前期约实例落定为解决期约后被调用。提供一个参数:value,当前期约实例落定为解决期约后的值。
-
函数(可选)
onRejected 处理程序(拒绝处理程序) ,在当前期约实例落定为拒绝期约后被调用,捕获并处理当前期实例约落定为拒绝期约后抛出的异步错误。提供一个参数:reason,当前期约实例落定为拒绝期约后的理由。
-
-
返回值:
期约,期约的状态会动态改变:-
初始状态
在排期的任务执行完毕之前,期约为待定期约。
-
落定状态
在排期的任务执行完毕之后,期约落定。
可能的落定状态:
- 继承当前期约实例的状态
情形:
- 没有提供处理程序
期约会继承当前期约实例的状态,并且继承当前期约实例的值。
- 解决
情形:
- 提供处理程序。
解决期约的值为处理程序的返回值。
如果处理程序没有返回值,则解决期约的值为 undefined 。
- 拒绝
情形:
- 在处理程序中抛出错误。
- 处理程序返回一个拒绝期约(即抛出异步错误)。
拒绝期约的理由为:
- 处理程序抛出的错误信息。
- 处理程序返回的拒绝期约的理由。
-
保持待定状态
情形:
- 处理程序返回一个待定期约。
切换到落定状态:
- 直到处理程序返回的待定期约落定后,期约才会根据返回期约的落定状态进行落定。
-
如果想要不提供解决处理程序,只提供拒绝处理程序,那么就在期约的原型方法 then() 的第一个参数上传入 null 。
这样有助于避免在内存中创建多余的对象,对期待函数参数的原型方法 then() 也是一个交代。
示例:
-
向期约实例添加解决处理程序。
// 创建解决期约 const promise = new Promise( (resolve, reject) => { setTimeout( () => { resolve(1) console.log('promise is resolved: ', promise) }, 1000 ) } ) // 打印此时的期约 promise console.log('promise is pending: ', promise) // 向期约 promise 添加解决处理程序,并接收返回的期约实例 const nextPromise = promise.then( (value) => { console.log('value of promise when resolved: ', value ) // 打印期约 promise 落定为解决期约后的值 return 2 } // 解决处理程序 ) // 向期约 promise 添加解决处理程序,打印期约 nextPromise promise.then( () => { console.log('nextPromise: ', nextPromise) } ) // 输出: // promise is pending: Promise {<pending>} // promise is resolved: Promise {<fulfilled>: 1} // value of promise when resolved: 1 // nextPromise: Promise {<fulfilled>: 2} -
向期约实例添加拒绝处理程序。
const promise = new Promise( (resolve, reject) => { setTimeout( () => { reject(3) console.log('promise is rejected: ', promise) }, 1000 ) } ) console.log('promise is pending: ', promise) const nextPromise = promise.then( null, // 不提供解决处理程序 (reason) => { console.log('reason of promise when rejected: ', reason ) // 打印期约 promise 落定为拒绝期约后的理由 return 4 } // 拒绝处理程序 ) promise.then( null, () => { console.log('nextPromise: ', nextPromise) } ) // 输出: // promise is pending: Promise {<pending>} // promise is rejected: Promise {<rejected>: 3} // reason of promise when rejected: 3 // nextPromise: Promise {<fulfilled>: 4} -
向期约实例添加解决处理程序、拒绝处理程序。
function start(randomState) { const promise = new Promise( (resolve, reject) => { setTimeout( () => { // 随机落定 switch(randomState) { case 0: resolve('resolved') console.log('promise is resolved: ', promise) break case 1: reject('rejected') console.log('promise is rejected: ', promise) break default: break } }, 1000 ) } ) const nextPromise = promise.then( (value) => { console.log('value of promise when resolved: ', value ) return 'resolved value' }, // 解决处理程序 (reason) => { console.log('reason of promise when rejected: ', reason ) return 'rejected reason' } // 拒绝处理程序 ) promise.then( () => { console.log('nextPromise: ', nextPromise) }, () => { console.log('nextPromise: ', nextPromise) } ) } const randomState = Math.round(Math.random()) start(randomState) // 可能的输出_01: // promise is resolved: Promise {<fulfilled>: 'resolved'} // value of promise when resolved: resolved // nextPromise: Promise {<fulfilled>: 'resolved value'} // 可能的输出_02: // promise is rejected: Promise {<rejected>: 'rejected'} // reason of promise when rejected: rejected // nextPromise: Promise {<fulfilled>: 'rejected reason'} -
在处理程序中抛出错误。
const promise = Promise.resolve() const nextPromise = promise.then( () => { throw 'error' // 抛出错误 } ) // 为期约 nextPromise_03 添加拒绝处理程序,捕获并处理异步错误 nextPromise.then( null, () => { console.log('nextPromise: ', nextPromise) console.log('error in nextPromise is resolved') } ) // 输出: // nextPromise: Promise {<rejected>: 'error'} // error in nextPromise is resolved -
处理程序返回待定期约。
const promise = Promise.resolve() const nextPromise = promise.then( () => { return new Promise( (resolve, reject) => { setTimeout(resolve, 1000) } ) // 返回一个 1s 后落定的待定期约 } ) setTimeout(console.log, 0, 'nextPromise:', nextPromise) setTimeout(console.log, 2000, 'nextPromise after 2s:', nextPromise) // 输出: // nextPromise: Promise {<pending>} // nextPromise after 2s: Promise {<fulfilled>: undefined}
Promise.prototype.catch()
期约的原型方法 catch() 用于为期约实例添加异步执行的拒绝处理程序。
期约的原型方法 catch() 会排期一个任务。
期约的原型方法 Promise.prototype.catch() :
-
功能:
为期约实例添加异步执行的拒绝处理程序。 -
接收一个参数(可选):
函数,onRejected 处理程序(拒绝处理程序),在当前期约实例落定为拒绝期约后被调用,捕获并处理当前期实例约落定为拒绝期约后抛出的异步错误。提供一个参数:reason,当前期约实例落定为拒绝期约后的理由。
-
返回值:
期约,期约的状态会动态改变:-
初始状态
在排期的任务执行完毕之前,期约处于待定状态。
-
落定状态
在排期的任务执行完毕之后,期约落定。
可能的落定状态:
- 继承当前期约实例的状态
情形:
- 没有提供处理程序
期约会继承当前期约实例的状态,并且继承当前期约实例的值。
- 解决
情形:
- 提供处理程序。
解决期约的值为处理程序的返回值。
如果处理程序没有返回值,则解决期约的值为 undefined 。
- 拒绝
情形:
- 在处理程序中抛出错误。
- 处理程序返回一个拒绝期约(即抛出异步错误)。
拒绝期约的理由为:
- 处理程序抛出的错误信息。
- 处理程序返回的拒绝期约的理由。
-
保持待定状态
情形:
- 处理程序返回一个待定期约。
切换到落定状态:
- 直到处理程序返回的待定期约落定后,期约才会根据返回期约的落定状态进行落定。
-
事实上期约的原型方法 catch() 是一个语法糖,相当于调用期约的原型方法 then(null, onRejected) 。
示例:
- 使用期约的原型方法 catch() ,向期约实例添加拒绝处理程序。
const promise = Promise.reject() const onRejected = function() { console.log('rejected is resolved') } const nextPromise = promise.catch(onRejected) // 添加拒绝处理程序 // 相当于 const nextPromise_01 = promise.then(null, onRejected) promise.catch(() => { console.log('nextPromise:', nextPromise) }) // 输出: // rejected is resolved // rejected is resolved // nextPromise: Promise {<fulfilled>: undefined}
Promise.prototype.finally()
期约的原型方法 finally() 用于为期约实例添加异步执行的最终处理程序。
期约的原型方法 finally() 会排期一个任务。
期约的原型方法 Promise.prototype.finally() :
-
功能:
为期约实例添加异步执行的最终处理程序。 -
接收一个参数(可选):
函数,onFinally 处理程序(姑且称为最终处理程序), 在当前期约实例落定后被调用,无论落定状态是解决还是拒绝。 -
返回值:
期约,期约的状态会动态改变:-
初始状态
在排期的任务执行完毕之前,期约处于待定状态。
-
落定状态
在排期的任务执行完毕之后,期约落定。
可能的落定状态:
- 继承当前期约实例的状态
情形:
- 没有提供处理程序
期约会继承当前期约实例的状态,并且继承当前期约实例的值。
- 解决
情形:
- 提供处理程序。
解决期约的值为处理程序的返回值。
如果处理程序没有返回值,则解决期约的值为 undefined 。
- 拒绝
情形:
- 在处理程序中抛出错误。
- 处理程序返回一个拒绝期约(即抛出异步错误)。
拒绝期约的理由为:
- 处理程序抛出的错误信息。
- 处理程序返回的拒绝期约的理由。
-
保持待定状态
情形:
- 处理程序返回一个待定期约。
切换到落定状态:
- 直到处理程序返回的待定期约落定后,期约才会根据返回期约的落定状态进行落定。
-
示例:
- 使用期约的原型方法 finally() ,向期约实例添加最终处理程序。
// 创建一个 1s 后落定为解决期约的期约实例 const promise = new Promise( (resolve, reject) => { setTimeout(resolve, 1000, 'promise') } ) const onFinally = function() { console.log('run onFinally()') return new Promise(() => {}) } const nextPromise = promise.finally(onFinally) // 添加最终处理程序 setTimeout(console.log, 1000, 'nextPromise:', nextPromise) // 输出: // run onFinally() // nextPromise: Promise {<pending>}
关于拒绝期约
如前所述,拒绝期约会抛出一个异步错误。
异步错误的值为拒绝期约的理由。
拒绝期约抛出的异步错误,只能由该拒绝期约的拒绝处理程序捕获并处理。
期约落定为拒绝期约表示 “以某个理由拒绝期约”。
期约落定为拒绝期约的情形:
-
在期约的执行函数中:
-
调用执行函数提供的函数 reject()。
期约的构造函数会返回一个拒绝期约,拒绝的理由为函数 reject() 的参数。
-
抛出错误。
期约的构造函数会返回一个拒绝期约,拒绝的理由为抛出的错误。
-
-
在期约的处理程序中:
-
返回一个拒绝期约。
相应的期约方法会返回一个拒绝期约,拒绝的理由为处理程序返回的拒绝期约的理由。
-
抛出错误。
相应的期约方法会返回一个拒绝期约,拒绝的理由为抛出的错误。
-
可以使用任何值作为错误信息抛出错误,但建议统一使用错误类型创建的错误对象。
因为浏览器可以捕获错误信息中的栈追踪信息,这些信息对调试是非常关键的。
示例:
- 在期约的执行函数中抛出错误。
const promise = new Promise( () => { throw new Error('error') // 抛出错误 } ) console.log('promise:', promise) // 捕获并处理错误 promise.catch( (reason) => { console.log('resolved the error:', reason) } ) // 输出: // Promise {<rejected>: Error: error // --at <anonymous>:3:10 // --at new Promise (<anonymous>) // --at <anonymous>:1:17 // resolved the error: Error: error // --at <anonymous>:3:10 // --at new Promise (<anonymous>) // --at <anonymous>:1:17
期约连锁
期约连锁,即期约调用原型方法生成一个新期约,而后这个新期约也调用原型方法生成一个新期约,如此循环,不断地生成新期约,将期约串联起来。
期约连锁中提供给期约的处理程序会按照对应期约落定的顺序执行。
期约连锁的应用:
-
异步顺序执行非异步代码。
简单地在处理程序中添加需要执行的非异步代码。
-
异步顺序执行异步代码。
在一个期约中添加需要执行的异步代码,并在异步代码中落定期约,然后在处理程序中返回这个期约。
如此,在返回期约落定之前,期约连锁的后续期约的处理程序不会被执行。
示例:
-
使用期约连锁异步顺序执行非异步代码。
const p = Promise.resolve() p.then( () => { console.log('run then() 01') } ).finally( () => { console.log('run then() 02') } ).then( () => { console.log('run then() 03') } ) // 输出: // run then() 01 // run then() 02 // run then() 03 -
使用期约连锁异步顺序执行异步代码。
const p = Promise.resolve() p.then( () => { return new Promise( (resolve) => { // 耗时 4s 的异步代码 setTimeout( () => { console.log('execute async code sequentially 01 consumed 4s ') resolve() // 落定期约 }, 4000 ) } ) } ) .then( () => { return new Promise( (resolve) => { // 耗时 2s 的异步代码 setTimeout( () => { console.log('execute async code sequentially 02 consumed 2s ') resolve() // 落定期约 }, 2000 ) } ) } ) .then( () => { return new Promise( (resolve) => { // 耗时 1s 的异步代码 setTimeout( () => { console.log('execute async code sequentially 03 consumed 1s ') resolve() // 落定期约 }, 1000 ) } ) } ) // 输出: // execute async code sequentially 01 consumed 4s // execute async code sequentially 02 consumed 2s // execute async code sequentially 03 consumed 1s
期约合成
类型 Promise 提供两个静态方法,用于根据多个期约合成一个期约:
- Promise.all()
- Promise.race()
Promise.all()
期约的静态方法 Promise.all() :
-
功能:
根据多个期约合成一个期约,返回的期约只有在所有期约落定为解决期约时才会落定为解决期约。 -
接收一个参数:
可迭代对象,可迭代对象中的元素:-
可迭代对象的元素不是期约
可迭代对象的元素会通过 Promise.resolve() 转换为解决期约。
-
可迭代对象中没有元素
方法 Promise.reolve() 会包装一个 undefined 值生成一个解决期约。
-
-
返回值:
期约,被称为合成期约,期约的状态会动态改变:-
待定
情形:
- 可迭代对象的期约中,至少有一个期约处于待定状态。
-
解决
情形:
- 可迭代对象的期约全部落定为解决期约。
合成解决期约的值为一个数组,数组的元素为可迭代对象的所有解决期约的值。
-
拒绝
情形:
- 可迭代对象的期约中,至少有一个期约落定为拒绝期约。
合成拒绝期约的理由为可迭代对象中的第一个拒绝期约的理由。
处理合成拒绝期约时,会静默处理可迭代对象中的其它拒绝期约。
-
示例:
-
可迭代对象的元素不是期约。
const iterable = ['01', '02', '03'] // 可迭代对象的元素不是期约 const compositePromise = Promise.all(iterable) setTimeout( () => { console.log('compositePromise', compositePromise) compositePromise.then( (values) => { // 合成解决期约的值为一个数组 values.forEach( (value, index) => { console.log(`value ${index}:`, value) } ) } ) }, 1000 ) // 输出 // compositePromise Promise {<fulfilled>: Array(3)} // value 0: 01 // value 1: 02 // value 2: 03 -
可迭代对象中包含待定期约。
const promises = [ Promise.resolve(), new Promise(() => {}) // 待定期约 ] const compositePromise = Promise.all(promises) setTimeout(console.log, 1000, 'compositePromise:', compositePromise) // 输出 // compositePromise: Promise {<pending>} -
可迭代对象中包含拒绝期约。
const promises = [ Promise.resolve(), Promise.reject('reason_01'), // 拒绝期约 Promise.reject('reason_02') ] const compositePromise = Promise.all(promises) compositePromise.catch( () => { console.log('compositePromise:', compositePromise) console.log('rejected is resolved') } ) // 输出 // compositePromise: Promise {<rejected>: 'reason_01'} // rejected is resolved
Promise.race()
期约的静态方法 Promise.race() :
-
功能:
根据多个期约合成一个期约,返回的期约是多个期约中第一个落定的期约的镜像。。 -
接收一个参数:
可迭代对象,可迭代对象中的元素:-
可迭代对象的元素不是期约
可迭代对象的元素会通过 Promise.resolve() 转换为期约。
-
可迭代对象中没有元素
空可迭代对象会转换为一个调用 new Promise(() => {}) 创建的待定期约。
-
-
返回值:
期约,被称为包装期约,期约的状态会动态改变:-
待定
情形:
- 可迭代对象的期约全部处于待定状态。
-
解决
情形:
- 可迭代对象的期约中,至少有一个期约落定为解决期约。
包装解决期约的值为可迭代对象中第一个解决期约的值。
-
拒绝
情形:
- 可迭代对象的期约中,至少有一个期约落定为拒绝期约。
包装拒绝期约的理由为可迭代对象中第一个拒绝期约的理由。
处理包装拒绝期约时,会静默处理可迭代对象中的其它拒绝期约。
-
可迭代对象的迭代顺序决定了期约的落定顺序。
示例:
- 可迭代对象中第一个落定的期约。
const promises = [ new Promise(() => {}), new Promise( (resolve) => { setTimeout( () => { resolve('01') console.log('resolved 01 consumed 2s ') }, 2000 ) } ), // 2s 后落定的期约 new Promise( (resolve) => { setTimeout( () => { resolve('02') console.log('resolved 02 consumed 1s ') }, 1000 ) } ) // 1s 后落定的期约 ] const packPromise = Promise.race(promises) packPromise.then( () => { console.log('packPromise:', packPromise) } ) // 输出 // resolved 02 consumed 1s // packPromise: Promise {<fulfilled>: '02'} // resolved 01 consumed 2s
期约合成值
利用期约的特性:期约落定时产生一个值,期约的值会被期约的处理程序作为参数接收。在期约落定时提供期约的值,并使用期约连锁逐级接收并加工上一级期约的值,最终得到一个值,姑且称为期约合成值。
示例:
-
使用期约连锁生成一个期约合成值。
// 处理程序 function handler_01(str) { return str + ' -> handler_01' // 加工期约值 } function handler_02(str) { return str + ' -> handler_02' } function handler_03(str) { return str + ' -> handler_03' } function compositeValue(str) { return Promise.resolve(str) .then(handler_01) .then(handler_02) .then(handler_03) // 期约连锁 } compositeValue('value').then(console.log) // 输出: // value -> handler_01 -> handler_02 -> handler_03 -
提炼出一个通用函数,可以把任意多个函数作为处理程序,利用期约连锁加工一个值。
function handler_01(str) { return str + ' -> handler_01' } function handler_02(str) { return str + ' -> handler_02' } function handler_03(str) { return str + ' -> handler_03' } // 通用函数 function compositeValue(...funcs) { return (value) => funcs.reduce( // 使用 Array 原型方法 reduce() (promise, func) => promise.then(func), Promise.resolve(value) ) } const composite = compositeValue(handler_01, handler_02, handler_03) composite('value').then(console.log) // 输出: // value -> handler_01 -> handler_02 -> handler_03 // 补充说明: // Array 原型方法 reduce(): // -- 第一个参数:归并函数,按顺序对每个数组元素执行该函数。 // ---- 提供的参数: // ------ 第一个参数:上一次执行归并函数返回的值。 // ------ 第二个参数:当前的数组元素。 // -- 第二个参数(可选):任意值,初始值,即对第一个数字元素执行归并函数时作为归并函数的第一个参数。 // -- 返回值: // ---- 任意值,最后执行归并函数返回的值。
本文详细介绍了JavaScript中的期约(Promise)机制,包括期约的状态机、创建期约实例、期约的落定、响应期约的落定、拒绝期约以及期约的连锁和合成。期约是ECMAScript实现异步编程的核心,通过Promise构造函数、Promise.resolve()和Promise.reject()等方法创建和管理期约。通过then()、catch()和finally()方法响应期约的落定,实现异步任务的顺序执行和错误处理。此外,还讲解了Promise.all()和Promise.race()的用法,用于组合多个期约。
509

被折叠的 条评论
为什么被折叠?



