1 Star 0 Fork 0

biyejun/cheny_codes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
test9.js 18.98 KB
一键复制 编辑 原始数据 按行查看 历史
cheny 提交于 2022-02-16 19:09 . docs: promise
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
const PEDNING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// then() 2.2
FULFILLED_CALLBACK_LIST = []
REJECTED_CALLBACK_LIST = []
/**
* 定义私有变量 _status,其对应的属性是构造器中的status
* 在使用getter、setter监听status时,我们操控 _status
* 防止死循环
* (
* 如果不用一个私有变量存储,那么在每次 对 status进行赋值和取值的操作时,
* 都会调用 setter和getter,这样就又是一波 赋值取值操作,然后就继续调用 setter和getter,
* 如此循环往复,成了死循环。
*
* 但是,当使用 _status 私有变量成员时,_status 并不会被getter、setter监听,
*
* )
*/
_status = PEDNING
/**
* @description 构造器,new MyPromise 会自动执行
* @param {Function<resolve,reject>} fn 接收的入参,是个函数,有resolve、reject两个参数
*
* 注意:在初始化promise的时候,就需要执行这个函数,并且有任何报错都要通过reject抛出去
* 所以,执行的时候用try...catch...包裹一下,使用bind绑定当前的this,防止出现乱起八糟的情况
*/
constructor(fn) {
// 初始状态为pending
this.status = PEDNING
this.value = null
this.reason = null
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
this.reject(e)
}
}
// then() 2.1
get status() {
return this._status
}
// then() 2.1
set status(newStatus) {
this._status = newStatus
switch (newStatus) {
case FULFILLED:
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
})
break;
case REJECTED:
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
})
break;
}
}
/**
* @description promise的resolve,成功时执行
* 做了两件事
* 1、设置自己的 value
* 2、将状态改为 FULFILLED
* 状态有两种流转方式,所以只有当前状态是 PENDING 时才允许改变,一旦改变不可逆
* pending -> resolve(value) -> fulfilled
* pending -> reject(reason) -> rejected
*
* @param {*} value 从外面传过来的值,可以是任意类型
*/
resolve(value) {
if (this.status === PEDNING) {
this.value = value
this.status = FULFILLED
}
}
/**
* @description promise的reject,失败时执行
* 做了两件事
* 1、设置自己的 reason
* 2、将状态改为 REJECTED
* 状态有两种流转方式,所以只有当前状态是 PENDING 时才允许改变,一旦改变不可逆
* pending -> resolve(value) -> fulfilled
* pending -> reject(reason) -> rejected
*
* @param {*} reason 从外面传过来的值,可以是任意类型
*/
reject(reason) {
if (this.status === PEDNING) {
this.reason = reason
this.status = REJECTED
}
}
/**
* @description promise的then方法
* @param {Function<value>} onFulfilled 成功时的回调
* @param {Function<reason>} onRejected 失败时的回调
*
* onFulfilled、onRejected必须为函数类型,如果不是函数类型,就忽略
* 忽略是指原样返回value或reason
*
* 1、先判断 onFulfilled、onRejected 是否为函数
* - onFulfilled 执行成功时的回调
* - onRejected 执行失败时的回调
* 2、then返回值是一个新的promise
* 2.1 根据当前promise的状态,调用不同的函数
* (
* 需要一个状态的监听机制,只有当状态变为 fulfilled 或者 rejected时,
* 才去执行对应的回调,可以使用 getter和setter 来监听属性值的变化
* )
* 补充:(函数的执行必须在微任务中,使用queueMicrotask包裹)
*
* 2.2 所以需要拿到所有的callback,在某个时机去执行它们
* 新建两个数组,分别存储成功和失败的回调,调用 then 方法时,
* 如果还是 pending 就先存入数组中,等到状态变为 fulfilled 或者 rejected时,
* 再从数组中拿出来执行
* 2.3 如果 执行 onFulfilled、onRejected 时,抛出一个异常e,则promise必须拒绝执行,
* 并返回拒绝原因e,手动 try...catch... 捕获一下
* 2.4 如果 onFulfilled 不是函数,且promise1 成功执行,promise2必须成功执行并返回相同的value。
* 2.5 如果 onFulfilled 不是函数,且promise1 拒绝执行,promise2必须拒绝执行并返回相同的reason。
* (需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve)
*/
then(onFulfilled, onRejected) {
// 1、
// 2.4
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value
}
// 1、
// 2.4
const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason
}
// 2、
const promise2 = new MyPromise((resolve, reject) => {
// 补充:(函数的执行必须在微任务中,使用queueMicrotask包裹)
const fulfilledMicrotask = () => {
queueMicrotask(() => {
// 2.3
try {
/**
* 并不确定传入的函数到底是个什么样的,平时我们写的时候最常见的是
* (res)=>{ console.log(res); this.xxxList = res.data; }
* 还有很多可能情况,所以我们需要处理一下这个函数的返回值,
* 看看到底是个什么种类的函数
*/
const x = realOnFulfilled(this.value)
// 这个函数有大量的if判断,待会详细看
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnRejected(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// 2.1
switch (this.status) {
case FULFILLED:
fulfilledMicrotask()
break;
case REJECTED:
rejectedMicrotask()
break;
case PEDNING:
// 2.2
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
break;
}
})
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
/*
无论成功失败,都会执行
*/
finally(callback) {
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value)
},
(err) => {
return MyPromise.resolve(callback()).then(() => { throw err })
}
)
}
/**
* @description 对promise .then 链式执行时的判断逻辑处理
* @param {Promise} promise2 执行完.then后返回的新的promise
* @param {*} x
* @param {*} resolve
* @param {*} reject
*
* 1、如果 newPromise 和 x 相等(===),以TypeError为因拒绝执行
* (为了防止死循环)
* 2、如果 x 是一个promise,newPromise就接收 x 的状态
* (
* 也就是继续执行x,
* 2.1 如果执行的时候拿到一个y,
* 递归 resolvePromise(promise2, y, resolve, reject),一直往下解析下去,
* 直到解析出别的条件为止
* )
* 3、如果 x 是一个对象或者函数
* 3.1 null 也会被判断为对象,单独处理一下
* if(x === null) return resolve(x)
* 3.2 let then = x.then
* (
* 注意,这里取值可能会报错,所以使用try...catch...包裹一下
* 当有报错时,直接reject(e)
* )
* 3.2.1 如果 then 是函数
* then.call(x, resolvePromiseFn, rejectPromiseFn)
* 将 x 作为函数的作用域this调用,传递两个回调函数作为参数 resolvePromiseFn和rejectPromiseFn
* - resolvePromiseFn:入参是 y,递归执行 resolvePromise(promise2, y, resolve, reject)
* - rejectPromiseFn:入参是 r,reject promise with r
* (
* 3.2.1.1 注意:需保证resolvePromiseFn和rejectPromiseFn只调用一次
* 所以,可以使用一个Boolean变量确定其是否被调用,初始值设为false,
* 当有函数被调用时改为true
*
* 3.2.1.2 另外:不能保证在调用then方法时会不会出错,所以也需要用try...catch...包裹一下
*
* 一旦出错,
* 3.2.1.3 如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
* 3.2.1.4 反之,reject promise with e as the reason
* )
*
* 3.2.2 如果 then 不是函数
* (
* 说明这个 x 就是一个单纯的对象,直接以 x 为参数执行 promise
* reslove(x)
* )
* 4、既不是promise,也不是对象,又不是函数,最后只能是基本类型了
* 以 x 为参数执行promise resolve(x)
*/
resolvePromise(promise2, x, resolve, reject) {
// 1、
if (promise2 === x) {
return reject(new TypeError('The promise and the return value are the same'))
}
// 2、
if (x instanceof MyPromise) {
queueMicrotask(() => {
// 2.1
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if (typeof x === 'object' || this.isFunction(x)) { // 3、
// 3.1
if (x === null) {
return resolve(x)
}
// 3.2
let then = null
try {
then = x.then
} catch (e) {
return reject(e)
}
// 3.2.1
if (this.isFunction(then)) {
// 3.2.1.1
let called = false
// 3.2.1.2
try {
then.call(
x,
(y) => {
if (called) return
called = true
this.resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
},
)
} catch (e) {
// 3.2.1.3
if (called) return
called = true
// 3.2.1.4
reject(e)
}
} else { // 3.2.2
resolve(x)
}
} else { // 4、
resolve(x)
}
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
/**
* @description 当iterableList中有一项执行完成,不管是fulfilled或者rejected,直接返回结果
* @param {Iterable} iterableList 入参必须是可迭代的
* @returns {Promise} 第一个执行出来的结果
*
* 需要注意:
* 1、入参必须是可迭代,含有Symbol.iterator属性
* 2、将类数组转换为数组 Array.from()
* 3、for循环默认是同步的,使用for循环遍历执行每一项promise
* 4、每一项都必须是promise对象,直接使用静态方法Promise.resolve(),全部转换为promise对象
* 5、只要有一个执行完成,不管是fulfilled或者rejected,直接返回
*/
static race(iterableList) {
return new MyPromise((resolve, reject) => {
// 1、
if (!MyPromise.isIterable(iterableList)) {
return reject(new TypeError(`${iterableList} is not iterable (cannot read property Symbol(Symbol.iterator))`))
}
// 2、
const promiseList = Array.from(iterableList)
const promiseLength = promiseList.length
if (promiseLength === 0) {
return resolve([])
} else {
// 3、
for (let i = 0; i < promiseLength; i++) {
// 4、
MyPromise.resolve(promiseList[i]).then(
(value) => {
// 5、
return resolve(value)
},
(reason) => {
// 5、
return reject(reason)
}
)
}
}
})
}
/**
* @description 当promiseList中所有项都fulfilled时,一块全返回出去,当有一个rejected,就直接reject出去
* @param {Iterable} iterableList 入参必须是可迭代的
* @returns {Promise} 返回所有执行完成的结果,当有一个rejected时,返回rejected的结果
*
* 需要注意:
* 1、入参必须是可迭代,含有Symbol.iterator属性
* 2、将类数组转换为数组 Array.from()
* 3、for循环默认是同步的,使用for循环遍历执行每一项promise
* 4、每一项都必须是promise对象,直接使用静态方法Promise.resolve(),全部转换为promise对象
* 5、将执行状态为fulfilled的结果存入一个临时数组中,所有的promise全部resolve时,把这个临时数组返回
* 6、只要有一个状态为rejected时,就直接返回rejected的结果
*/
static all(iterableList) {
return new MyPromise((resolve, reject) => {
// 1、
if (!MyPromise.isIterable(iterableList)) {
return reject(new TypeError(`${iterableList} is not iterable (cannot read property Symbol(Symbol.iterator))`))
}
// 2、
const promiseList = Array.from(iterableList)
const promiseLength = promiseList.length
let resolvedCount = 0
let resolvedValues = new Array(promiseLength)
if (promiseLength === 0) {
return resolve([])
} else {
// 3、
for (let i = 0; i < promiseLength; i++) {
// 4、
MyPromise.resolve(promiseList[i]).then(
(value) => {
resolvedCount++
// 5、
resolvedValues[i] = value
if (resolvedCount === promiseLength) {
return resolve(resolvedValues)
}
},
(reason) => {
// 6、
return reject(reason)
},
)
}
}
})
}
/**
* @description 判断是否为函数
* @param {*} param
* @returns {Boolean} true:是函数;false:不是函数
*/
isFunction(param) {
return typeof param === 'function'
}
/**
* @description 判断value是否可迭代
* @param {*} value
* @returns {Boolean} true:可迭代;false:不可迭代
*/
static isIterable(value) {
if (value === null || value === undefined) {
return false
} else {
return !(value[Symbol.iterator] === undefined)
}
}
}
/* const promise1 = 1
const promise2 = MyPromise.resolve(2)
const promise3 = MyPromise.reject(3) */
/* MyPromise.all([promise1, promise2, promise3]).then(
(value) => {
console.log(value, 'onFulfilled');
},
(reason) => {
console.log(reason, 'onRejected');
}
) */
/* MyPromise.all(null).then(
(value) => {
console.log(value, 'onFulfilled');
},
(reason) => {
console.log(reason, 'onRejected');
}
) */
/* MyPromise.all([]).then(
(value) => {
console.log(value, 'onFulfilled');
},
(reason) => {
console.log(reason, 'onRejected');
}
) */
/* MyPromise.race([promise3, promise1]).then(
(value) => {
console.log(value, 'onFulfilled');
},
(reason) => {
console.log(reason, 'onRejected');
}
) */
/* let test = new MyPromise((resolve, reject) => {
resolve(111)
}).then(
(value) => {
console.log(value)
// 假设执行完这个回调后,又返回了一个Promise
//
return (resolve, reject) => {
resolve('222')
}
}
) */
/* let test = new MyPromise((resolve, reject) => {
resolve(111)
}).then(
(value) => {
console.log(value)
// 假设执行完这个回调后,又返回了一个Promise
//
return {
a: 'aaa',
b: 'bbb',
then: (resolve, reject) => {
resolve(2222)
}
}
}
) */
/* let test = new MyPromise((resolve, reject) => {
resolve(111)
}).then(
(value) => {
console.log(value)
// 假设执行完这个回调后,又返回了一个Promise
//
return {
a: 'aaa',
b: 'bbb',
then: (resolve, reject) => {
console.log('22222');
reject('333');
}
}
}
) */
let test = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(111)
resolve(111)
}, 1000)
}).then(
(value) => {
console.log(value, 'fulfilled')
},
(reason) => {
console.log(reason, 'rejected')
},
)
test.then(console.log)
console.log(test)
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/hrbust_cheny/note_code.git
git@gitee.com:hrbust_cheny/note_code.git
hrbust_cheny
note_code
cheny_codes
master

搜索帮助