函数柯里化
Currying 又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化 作为一种高阶技术, 可以提升函数的复用性和灵活性。
什么是函数柯里化
函数柯里化 (Currying) 是一种将多个参数的函数转换为单个参数函数的技术
转换完毕之后的函数:只传递函数的一部分参数来调用,让他返回一个新的函数去处理剩下的参数。
例子:
1 2 3 4 5 6 7
| function sum(num1, num2) { return num1 + num2 }
console.log(sum(1)(2))
|
核心步骤:
sum
改为接收一个参数,返回一个新函数
- 新函数内部将参数1,参数2累加并返回
1 2 3 4 5
| function sum(num1) { return function (num2) { return num1 + num2 } }
|
柯里化面试题-全局变量
柯里化在面试的时候一般以笔试题出现,比如
需求:
1 2 3 4 5 6 7 8
| function sum(a, b, c, d, e) { return a + b + c + d + e }
|
核心步骤:
- 接收不定长参数
- 存储已传递的参数
- 判断长度
- 满足5:累加
- 不满足:继续返回函数本身
1 2 3 4 5 6 7 8 9 10 11 12
| let nums = [] function currySum(...args) { nums.push(...args) if (nums.length >= 5) { return nums.reduce((prev, curv) => prev + curv, 0) } else { return currySum } }
|
柯里化面试题-使用闭包
需求:
- 使用闭包将上一节代码中的全局变量,保护起来
- 支持自定义累加的参数个数
1 2 3 4 5 6 7 8
| function sumMaker(length){ }
const sum5 = sumMaker(5)
const sum7 = sumMaker(7) sum7(1,2,3)(4,5,6,7)
|
核心步骤:
- 定义外层函数:
- 定义参数
length
- 将全局变量迁移到函数内
- 定义内层函数:
- 参数长度判断,使用传入的参数
length
- 直接复用上一节的逻辑,并返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function sumMaker(length) { let nums = [] function inner(...args) { nums.push(...args) if (nums.length >= length) { return nums.reduce((prev, curv) => prev + curv, 0) } else { return inner } } return inner }
const sum5 = sumMaker(5) console.log(sum5(1,2,3)(4)(5))
const sum7 = sumMaker(7) sum7(1,2,3)(4,5,6,7)
|
柯里化实际应用-类型判断
通过参数复用,实现一个类型判断生成器函数
需求:
- 将下列4个类型判断函数,改写为通过函数
typeOfTest
动态生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function isUndefined(thing) { return typeof thing === 'undefined' } function isNumber(thing) { return typeof thing === 'number' } function isString(thing) { return typeof thing === 'string' } function isFunction(thing) { return typeof thing === 'function' }
const typeOfTest =function(){
} const isUndefined = typeOfTest('undefined') const isNumber = typeOfTest('number') const isString = typeOfTest('string') const isFunction = typeOfTest('function')
isUndefined(undefined) isNumber('123') isString('memeda') isFunction(() => { })
|
核心步骤:
typeOfTest
接收参数type
用来接收判断的类型
- 内部返回新函数,接收需要判断的值,并基于
type
进行判断
- 使用箭头函数改写为最简形式~~传送门
1
| const typeOfTest = type => thing => typeof thing === type
|
柯里化实际应用-固定参数
依旧是一个参数复用的实际应用
需求:
- 将如下3个请求的函数(都是post请求),变为通过
axiosPost
函数动态生成
- 实现函数
axiosPost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| axios({ url: 'url1', method: 'post', data: {} }) axios({ url: 'url2', method: 'post', data: {} }) axios({ url: 'url3', method: 'post', data: {} })
const axiosPost = () => { }
axiosPost('url1', data1) axiosPost('url2', data2) axiosPost('url3', data3)
|
核心步骤:
- 函数内部固定请求方法,post
- 函数内部调用
axios
发请求即可
axios
内部就是这样实现的传送门:
1 2 3 4 5 6
| const axiosPost = (url, data) => { return axios({ url, data, method: 'post' }) }
|
小结:
函数柯里化是一种函数式编程思想:将多个参数的函数转换为单个参数函数,调用时返回新的函数接收剩余参数
常见面试题
1 2 3 4 5 6 7 8
| function sum(a, b, c, d, e) { return a + b + c + d + e }
|
常见应用:固定参数,比如axios
中的:
- 类型判断函数
- get,post,put等别名方法
手写Promise
- 实现Promise的核心用法
- Promise的静态方法
- 实现Promise的静态方法
首先明确Promise的核心用法
1 2 3 4 5 6 7 8 9 10 11 12 13
| const p = new Promise((resolve, reject) => { resolve('success') })
p.then(res => { console.log(res) }, err => { console.log(err) })
|
手写Promise-构造函数
需求:
- 实现MyPromise类,可以用如下的方式实例化
- 实例化时传入回调函数
- 回调函数立刻执行
- 回调函数接收函数
resolve
和reject
1 2 3 4
| const p = new MyPromise((resolve, reject) => { })
|
核心步骤:
- 定义类
MyPromise
- 实现构造函数,接收
executor
–传入的回调函数
- 构造函数中定义
resolve
和reject
并传入executor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class MyPromise { constructor(executor) { const resolve = () => { console.log('resolve-call') } const reject = () => { console.log('reject-call') } executor(resolve, reject) } }
|
手写Promise-状态、成功or失败原因
需求:
MyPromise
增加state
属性,只能是如下3个值
pending
:待定,默认状态
fulfilled
:已兑现,操作成功
rejected
:已拒绝,操作失败
MyPromise
增加result
属性,记录成功/失败原因
- 调用
resolve
或reject
,修改状态,并记录成功/失败原因
1 2 3 4 5
| const p = new MyPromise((resolve, reject) => { reject('失败原因') }) console.log(p)
|
核心步骤:
- 定义常量保存状态,避免硬编码
MyPromise
中定义
- 属性:
state
保存状态,result
成功/失败原因
- 修改
state
的私有方法,修改状态并记录result
- 注意:
state
只有在pending
时,才可以修改,且不可逆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) } const reject = (result) => { this.#changeState(REJECTED, result) } executor(resolve, reject) }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } }
|
手写Promise-then方法的核心功能
需求:
- then方法的回调函数1: 状态变为
fulfilled
时触发,并获取成功结果
- then方法的回调函数2: 状态变为
rejected
时触发,并获取失败原因
- then方法的回调函数1或2没有传递的特殊情况处理,参考:then方法的参数
1 2 3 4 5 6 7 8 9 10 11
| const p = new MyPromise((resolve, reject) => { reject('失败原因') })
p.then(res => { console.log('success:', res) }, err => { console.log('error:', err) })
|
核心步骤:
- 增加
then
方法,根据不同的状态执行对应的回调函数,并传入result
- 参数1:成功的回调函数
- 参数2:失败的回调函数
- 没有传递
onFulfilled
,onRejected
时,设置默认值(参考文档)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) } const reject = (result) => { this.#changeState(REJECTED, result) } executor(resolve, reject) }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } if (this.state === FULFILLED) { onFulfilled(this.result) } else if (this.state === REJECTED) { onRejected(this.result) } } }
|
手写Promise-then方法支持异步和多次调用(非链式)
需求:
- 实例化传入的回调函数,内部支持异步操作
- then方法支持多次调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const p = new MyPromise((resolve, reject) => { setTimeout(() => { reject('失败原因') }, 2000) })
p.then(res => { console.log('success1:', res) }, err => { console.log('error1:', err) }) p.then(res => { console.log('success2:', res) }, err => { console.log('error2:', err) }) p.then(res => { console.log('success3:', res) }, err => { console.log('error3:', err) })
|
核心步骤:
- 定义属性,保存传入的回调函数:[]
- 调用
then
方法并且状态为pending
时保存传入的成功/失败回调函数
- 调用
resolve
和reject
时执行上一步保存的回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected } = this.handlers.shift() if (this.state === FULFILLED) { onFulfilled(this.result) } else { onRejected(this.result) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} if (this.state === FULFILLED) { onFulfilled(this.result) } else if (this.state === REJECTED) { onRejected(this.result) } else { this.handlers.push({ onFulfilled, onRejected }) } } }
|
手写Promise-链式编程-成功状态+普通返回值
需求:
then
的链式编程
- 目前只考虑
resolve
内部返回普通值的情况
1 2 3 4 5 6 7 8 9 10 11 12 13
| const p = new MyPromise((resolve, reject) => { resolve(1) }) p.then(res => { console.log(res) return 2 }).then(res => { console.log(res) return 3 }).then(res => { console.log(res) return 4 })
|
核心步骤:
- 调整
then
方法,返回一个新的MyPromise
对象
- 内部获取
onFulfilled
的执行结果,传入resolve
方法继续执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected } = this.handlers.shift() if (this.state === FULFILLED) { onFulfilled(this.result) } else { onRejected(this.result) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} const p2 = new MyPromise((resolve, reject) => { if (this.state === FULFILLED) { const res = onFulfilled(this.result) resolve(res) } else if (this.state === REJECTED) { onRejected(this.result) } else { this.handlers.push({ onFulfilled, onRejected }) } }) return p2 } }
|
手写Promise-链式编程-成功状态+返回Promise
需求:
then
的链式编程
- 目前考虑
resolve
内部返回MyPromise
的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const p = new MyPromise((resolve, reject) => { resolve(1) }) p.then(res => { console.log(res) return new MyPromise((resolve, reject) => { resolve(2) }) }).then(res => { console.log(res) return new MyPromise((resolve, reject) => { resolve(3) }) }).then(res => { console.log(res) })
|
核心步骤:
- 内部获取
onFulfilled
的执行结果:
- 如果是
MyPromise
实例,继续then
下去并传入resolve
和reject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected } = this.handlers.shift() if (this.state === FULFILLED) { onFulfilled(this.result) } else { onRejected(this.result) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} const p2 = new MyPromise((resolve, reject) => { if (this.state === FULFILLED) { const res = onFulfilled(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { resolve(res) } } else if (this.state === REJECTED) { onRejected(this.result) } else { this.handlers.push({ onFulfilled, onRejected }) } }) return p2 } }
|
手写Promise-链式编程-失败状态
需求:
then
的第二个回调函数,执行reject
时的链式编程
1 2 3 4 5 6 7 8 9 10 11 12
| const p = new MyPromise((resolve, reject) => { resolve(1) })
p.then(res => { console.log(res) return new MyPromise((resolve, reject) => { reject(2) }) }).then(undefined, err => { console.log('err:', err) })
|
核心步骤:
- 参考
resolve
的逻辑
- 先实现功能,再抽取为函数直接调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected } = this.handlers.shift() if (this.state === FULFILLED) { onFulfilled(this.result) } else { onRejected(this.result) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }; const p2 = new MyPromise((resolve, reject) => { if (this.state === FULFILLED) { this.#runPromise(onFulfilled, resolve, reject) } else if (this.state === REJECTED) { this.#runPromise(onRejected, resolve, reject) } else { this.handlers.push({ onFulfilled, onRejected }) } }) return p2 } #runPromise(callback, resolve, reject) { const res = callback(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { this.state === FULFILLED ? resolve(res) : reject(res) } } }
|
手写Promise-链式编程-支持异步
需求:
- 执行异步操作时,支持链式编程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve(1) }, 2000) })
p.then(res => { console.log(res) return new MyPromise((resolve, reject) => { setTimeout(() => { reject(2) }, 2000) }) }) .then(undefined, err => { console.log('err:', err) })
|
核心步骤:
- then的内部将
resolve
,reject
也推送到数组中
- 调整
runHandlers
函数,内部直接调用runPromise
函数即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result) this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected, resolve, reject } = this.handlers.shift() if (this.state === FULFILLED) { this.#runPromise(onFulfilled, resolve, reject) } else { this.#runPromise(onRejected, resolve, reject) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }; const p2 = new MyPromise((resolve, reject) => { if (this.state === FULFILLED) { this.#runPromise(onFulfilled, resolve, reject) } else if (this.state === REJECTED) { this.#runPromise(onRejected, resolve, reject) } else { this.handlers.push({ onFulfilled, onRejected, resolve, reject }) } }) return p2 } #runPromise(callback, resolve, reject) { const res = callback(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { this.state === FULFILLED ? resolve(res) : reject(res) } } }
|
手写Promise-使用微任务
需求:
- 如下代码打印结果为
1,2,4,3
1 2 3 4 5 6 7 8 9
| console.log(1) const p = new MyPromise((resolve, reject) => { console.log(2) resolve(3) }) p.then(res => { console.log(res) }) console.log(4)
|
核心步骤:
- 使用
queueMicrotask
包裹runPromise
的内部逻辑即可
- 传送门:MDN-queueMicrotask
- 传送门:MDN-queueMicrotask使用指南
1 2 3 4 5 6 7 8 9 10 11
| #runPromise(callback, resolve, reject) { queueMicrotask(() => { const res = callback(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { this.state === FULFILLED ? resolve(res) : reject(res) } }) }
|
小结:
手写Promise
的核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected'
class MyPromise { state = PENDING result = undefined handlers = []
constructor(executor) { const resolve = (result) => { this.#changeState(FULFILLED, result)
this.#runHandlers() } const reject = (result) => { this.#changeState(REJECTED, result) this.#runHandlers() } executor(resolve, reject) }
#runHandlers() { while (this.handlers.length > 0) { const { onFulfilled, onRejected, resolve, reject } = this.handlers.shift() if (this.state === FULFILLED) { this.#runPromise(onFulfilled, resolve, reject) } else { this.#runPromise(onRejected, resolve, reject) } } }
#changeState(state, result) { if (this.state !== PENDING) { return } this.state = state this.result = result }
then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
const p2 = new MyPromise((resolve, reject) => { if (this.state === FULFILLED) { this.#runPromise(onFulfilled, resolve, reject) } else if (this.state === REJECTED) { this.#runPromise(onRejected, resolve, reject) } else { this.handlers.push({ onFulfilled, onRejected, resolve, reject }) } }) return p2 }
#runPromise(callback, resolve, reject) { queueMicrotask(() => { const res = callback(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { this.state === FULFILLED ? resolve(res) : reject(res) } }) } }
|
手写Promise-实例方法catch
需求:
- 实现实例方法
catch
,可以实现如下调用
1 2 3 4 5 6 7 8
| const p = new MyPromise((resolve, reject) => { reject(1) }) p.then(res => { console.log(res) }).catch(err => { console.log('err:', err) })
|
核心步骤:
- 参考文档,catch等同于:
then(undefined,onRjected)
- 直接添加
catch
方法,内部调用then
- 使用
try-catch
包裹runPromise
,出错时,调用reject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
catch(onRjected) { return this.then(undefined, onRjected) }
#runPromise(callBack, resolve, reject) { queueMicrotask(() => { try { const res = callBack(this.result) if (res instanceof MyPromise) { res.then(resolve, reject) } else { if (this.state === FULFILLED) { resolve(res) } else if (this.state === REJECTED) { reject(res) } } } catch (error) { return reject(error) } })
|
手写Promise-实例方法finally
需求:
- 无论成功失败都会执行
finally
的回调函数
- 回调函数不接受任何参数
1 2 3 4 5 6 7 8 9 10 11
| const p = new Promise((resolve, reject) => { reject('error') })
p.then(res => { console.log(res) }).catch(err => { console.log(err) }).finally(() => { console.log('finally执行啦') })
|
核心步骤:
- 参考文档:finally方法类似于调用
then(onFinally,onFinally)
,且不接受任何回调函数
1 2 3 4 5 6
| finally(onFinally) { return this.then(onFinally,onFinally) }
|
手写Promise-静态方法resolve
需求:
- 返回一个带有成功原因的
Promise
对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| MyPromise.resolve(2).then(res => { console.log(res) }) const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
MyPromise.resolve(p).then(res => { console.log(res) })
|
核心步骤:
- 增加静态方法
resolve
,根据传入的值返回不同的结果即可
1 2 3 4 5 6 7 8 9 10 11 12
| static resolve(value) { if (value instanceof MyPromise) { return value } return new MyPromise((resolve, reject) => { resolve(value) }) }
|
手写Promise-静态方法reject
需求:
- 返回一个带有拒绝原因的
Promise
对象
1 2 3
| MyPromise.reject('error').catch(err => { console.log(err) })
|
核心步骤:
- 添加静态方法内部返回有拒绝原因的
Promise
对象即可
1 2 3 4 5
| static reject(err) { return new MyPromise((resolve, reject) => { reject(err) }) }
|
这个两个方法在axios拦截器里可以发现到。
手写Promise-静态方法race
需求:
- 接收Promise数组
- 第一个Promise成功或失败时,返回一个该Promise对象及原因
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const promise1 = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('one') }, 500) })
const promise2 = new MyPromise((resolve, reject) => { setTimeout(() => { reject('two') }, 100) })
MyPromise.race([promise1, promise2]).then((value) => { console.log('value:',value) }, err => { console.log('err:', err) })
|
核心步骤:
- 内部返回新的Promise对象:
- 参数判断:
- 不是数组:报错
- 是数组:挨个解析
- 任意一个Promise对象成功或失败,直接resolve或reject即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static race(promises) { return new MyPromise((resolve, reject) => { if (Array.isArray(promises)) { promises.forEach(item => { MyPromise.resolve(item).then(resolve, reject) }) } else { return reject(new TypeError('Argument is not iterable')) } }) }
|
手写Promise-静态方法all
需求:
- 接收Promise数组,
- 所有Promise都成功时,返回一个成功的Promise对象及成功数组
- 任何一个Promise失败,返回一个失败的Promise对象及第一个失败原因
1 2 3 4 5 6 7 8 9 10 11
| const promise1 = MyPromise.resolve(3); const promise2 = 42; const promise3 = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000); });
MyPromise.all([promise1, promise2, promise3]).then((values) => { console.log(values); });
|
核心步骤:
包裹一个新的Promise并返回,内部进行参数校验
非数组:报错
数组:循环挨个解析
长度为0:直接返回成功状态的Promise
长度不为0:挨个解析:forEach
不是Promise对象:直接记录结果并判断是否解析完毕
是Promise对象:调用then
- 成功:记录结果并判断是否解析完毕
- 失败:直接reject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| static all(promises) { return new MyPromise((resolve, reject) => { if (Array.isArray(promises)) { const result = [] let count = 0 if (promises.length === 0) { return resolve(promises) } promises.forEach((item, index) => { if (item instanceof MyPromise) { item.then(res => { count++ result[index] = res count === promises.length && resolve(result) }, err => { reject(err) }) } else { count++ result[index] = item count === promises.length && resolve(result) } }) } else { return reject(new TypeError('Argument is not iterable')) } }) }
|
手写Promise-静态方法allSettled
需求:
- 传入Promise数组,当所有对象都已敲定时
- 返回一个新的Promise对象及以数组形式保存的结果
1 2 3 4 5 6 7 8 9 10 11
|
const promise1 = Promise.resolve('1'); const promise2 = new Promise((resolve, reject) => setTimeout(() => { reject('two') }, 1000)); const promises = [promise1, promise2];
Promise.allSettled(promises). then((results) => { console.log(results) })
|
核心步骤:
- 增加静态方法
allSettled
- 内部逻辑和
all
类似,需要特别注意的地方:
- 成功和失败的原因都会通过对象记录起来
- 返回一个记录了成功
{state:FULFILLED,value:'xxx'}
失败{state:REJECTED,reason:'xxx'}
的结果数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| static allSettled(promises) { return new MyPromise((resolve, reject) => { if (Array.isArray(promises)) { let result = [] let count = 0 if (promises.length === 0) return resolve(promises)
promises.forEach((item, index) => { MyPromise.resolve(item).then(value => { count++ result[index] = { state: FULFILLED, value } count === promises.length && resolve(result) }, reason => { count++ result[index] = { state: REJECTED, reason } count === promises.length && resolve(result) }) }) } else { return reject(new TypeError('Argument is not iterable')) } }) }
|
手写Promise-静态方法any
需求:-传送门
- 传入
Promise
数组,
- 任何一个
Promise
对象敲定时,返回一个新的Promise
对象,及对应的结果
- 所有Promise都被拒绝时,返回一个包含所有拒绝原因的
AggregateError
错误数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const promise1 = new MyPromise((resolve, reject) => { setTimeout(() => { reject('error1') }, 2000); }); const promise2 = new MyPromise((resolve, reject) => { setTimeout(() => { reject('error2') }, 3000); }); const promise3 = new MyPromise((resolve, reject) => { setTimeout(() => { reject('error3') }, 1000); });
MyPromise.any([promise1, promise2, promise3]).then((values) => { console.log(values); }, err => { console.log('err:', err) })
|
核心步骤:
- 类似于
all
核心区别
- 数组长度为0,直接返回错误数组
- 任何一个成功,直接成功
- 通过数组记录失败原因,都失败时响应错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| static any(promises) { return new MyPromise((resolve, reject) => { if (Array.isArray(promises)) { let errors = [] let count = 0 if (promises.length === 0) return reject(new AggregateError('All promises were rejected'))
promises.forEach(item => { item.then(value => { resolve(value) }, reason => { count++ errors.push(reason) count++ === promises.length && reject(new AggregateError(errors))
}) }) } else { return reject(new TypeError('Argument is not iterable')) } }) }
|
promise需要掌握的点:
组织异步,回调函数 => 链式编程
async await : await会等待后面Promise成功,并获取结果,try-catch捕获异常
多个异步管理:
all :都成功,第一个失败
race:第一个成功或失败
allSettled: 所有都敲定(成功/失败),以对象数组的形式获取结果
1 2 3 4 5 6 7 8 9 10
| [ { value: '成功原因', status:'fulfilled' }, { reason: '失败原因' status:'rejected' } ]
|
any : 第一个成功,或者都失败
被追问:用在哪里:
all:多个接口数据,获取完毕再渲染
race: 多个服务器的相同接口,都可以获取同一份数据,为了让用户尽可能的拿到结果,race调用相同的多个接口,只要拿到就渲染。
1.服务器1–新闻接口
2.服务器2–新闻接口
3.同时调用,哪个先获取到,就直接渲染
allSettled,any 了解过代码
手写promise
- 构造函数:传入回调函数,并接收resolve和reject
- 状态和成功/失败结果:
- 定义常量保存状态,定义实例属性保存状态和结果
- resolve和reject中修改状态记录结果
- then方法
- 多次调用:用数组来保存回调函数
- 链式调用:内部返回Promise
- 实例方法:
- catch: 本质就是 then(undefined,onRejected)
- finally: 本质 then(onFinally,onFinally)
- 静态方法