1 Star 4 Fork 0

Fan/线上考试系统

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
手写Promise.js 24.76 KB
一键复制 编辑 原始数据 按行查看 历史
Fan 提交于 2022-06-14 17:36 . 手写Promise
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
// Promise
// 一种处理异步代码(而不会陷入回调地狱)的方式
// 异步函数在底层使用了 promise ,因此了解 promise 的工作方式是了解 async 和 await 的基础
// Promise 对象代表一个异步操作,有 pending(进行中) fulfilled(成功) rejected(失败) 三个状态
// 运作过程:
// 当 Promise 被调用后,进入 pending 状态。这意味着调用的函数会继续执行,而 Promise 仍处于 pending 知道解决为止,从而为调用函数提供所请求的任何数据
// 被创建的 Promise 最终以 fulfilled 或 rejected 状态结束,并在完成时调用相应的回调函数(传给 then 和 catch)
// 特点:
// 执行 resolve、reject ,Promise 状态分别会变成 fulfilled、rejected,其中 Promise 中有 throw 相当于执行 reject
// Promise 没有执行 resolve、reject、throw, Promise 状态不变为 pending
// pending 状态下的 Promise 不会执行回调函数 then()
// Promise 必须传入一个执行函数,否则会报错
// Promise 一旦发生状态改变就是永久的
// 在本轮 事件循环 运行完成之前,回调函数是不会被调用的。
// 即使异步操作已经完成(成功或失败),在这之后通过 then() 添加的回调函数也会被调用。
// 通过多次调用 then() 可以添加多个回调函数,它们会按照插入顺序进行执行。
class myPromise {
static PENDING = 'pending'
static FULIIIED = 'fulilled'
static REJECTED = 'rejected'
// constructor 指向实力原型的构造函数
constructor(func) {
this.PromiseState = myPromise.PENDING
this.PromiseResult = null
this.onFulfilledCallbacks = [] // 保存成功回调
this.onRejectedCallbacks = [] // 保存失败回调
try {
// new 一个新实例的时候执行的是 constructor中的内容,即 constructor 中的this指向新实例,
// 但我们在新实例被创建后的外部使用 resolve ,就相当于不在 class 内部使用该 this
// 所以要给 resolve 和 reject 绑定 this 为当前的实例对象,待创建实例调用后才执行 所以使用 bind
func(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
// 这里不需要给 reject 方法进行 this 绑定了,这里是直接执行而不是创建实例后再执行
this.reject(error)
}
}
// then 是在创建实例后再进行调用的,所以要再创建一个类方法
// Promise 规定then方法里面的两个参数如果不是函数的话就要被忽略
// then方法本身会返回一个新的Promise对象,返回一个新的Promise以后它就有自己的then方法,这样就能实现无限的链式
// 不论 promise1 被 resolve() 还是被 reject() 时 promise2 都会执行 Promise 解决过程:[[Resolve]](promise2, x)
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } // 不理解
const promise2 = new myPromise((resolve, reject) => {
if (this.PromiseState === myPromise.PENDING) {
// 为了保留 then 里的函数,我们创建 数组来保存函数
// 为很么使用数组保存回调? 一个 Promise 实例可能会多次 then,即链式调用,而数组是先入先出顺序
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.PromiseResult)
// 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.PromiseResult)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
}
// onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用
// 平台代码指的是引擎、环境以及 promise 的实施代码
// 实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。
// 这个事件队列可以采用“宏任务(macro-task)”机制,比如setTimeout 或者 setImmediate
// 也可以采用“微任务(micro-task)”机制来实现, 比如 MutationObserver 或者process.nextTick
else if (this.PromiseState === myPromise.FULIIIED) {
// 设置异步执行,在 if 中添加以确保状态不处于pending
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e) // 捕获前面onFulfilled中抛出的异常
}
})
}
else if (this.PromiseState === myPromise.REJECTED) {
// 设置异步执行,在 if 中添加以确保状态不处于pending
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
}
})
return promise2
}
resolve(result) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.FULIIIED
this.PromiseResult = result
this.onFulfilledCallbacks.forEach(callback => {
callback(result)
})
})
}
}
reject(reason) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.REJECTED
this.PromiseResult = reason
this.onRejectedCallbacks.forEach(callback => {
callback(reason)
})
});
}
}
}
/**
* 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
* @param {promise} promise2 promise1.then方法返回的新的promise对象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
function resolvePromise(promise2, x, resolve, reject) {
// 如果 promise 和 x 指向同一对象,以 TypeError 为因(循环引用报错)拒绝执行 promise
if (x === promise2) { return reject(new TypeError('Chaining cycle detected for promise')) }
// 2.3.2 如果 x 为 Promise ,则使 promise2 接受 x 的状态
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
/**
* 2.3.2.1 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
* 注意"直至 x 被执行或拒绝"这句话,
* 这句话的意思是:x 被执行x,如果执行的时候拿到一个y,还要继续解析y
*/
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject)
}else if (x.PromiseState === myPromise.FULFILLED){
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
}else if (x.PromiseState === myPromise.REJECTED){
// 2.3.2.2 如果 x 处于拒绝行态,用相同的据因拒绝 promise
reject(x.PromiseResult)
}else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 2.3.3 如果 x 为对象或函数
try {
// 2.3.3.1 把 x.then 赋值给 then
var then = x.then;
} catch (e) {
// 2.3.3.2 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(e)
}
}
/**
* 2.3.3.3
* 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
* 传递两个回调函数作为参数,
* 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
*/
if (typeof then === 'function') {
// 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false // 避免多次调用
try {
then.call(
x,
// 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y => {
if (called) { reutrn }
called = true
resolvePromise(promise2, y, resolve, reject)
},
// 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r => {
if (called) { return }
called = true
reject(r)
}
)
} catch (e) {
/**
* 2.3.3.3.4 如果调用 then 方法抛出了异常 e
* 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
*/
if (called) { return }
// 2.3.3.3.4.2 否则以 e 为据因拒绝 promise
reject(e)
}
} else {
// 2.3.3.4 如果 then 不是函数,以 x 为参数执行 promise
resolve(x)
}
} else {
// 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
return resolve(x);
}
}
// setTimeout()属于宏任务 promise.then()属于微任务
// 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。
// 同一次事件循环中,微任务永远在宏任务之前执行。
// 按步分析 注释加持版
class myPromise {
// 为了统一用static创建静态属性,用来管理状态
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
// 构造函数:通过new命令生成对象实例时,自动调用类的构造函数
constructor(func) { // 给类的构造方法constructor添加一个参数func
this.PromiseState = myPromise.PENDING; // 指定Promise对象的状态属性 PromiseState,初始值为pending
this.PromiseResult = null; // 指定Promise对象的结果 PromiseResult
this.onFulfilledCallbacks = []; // 保存成功回调
this.onRejectedCallbacks = []; // 保存失败回调
try {
/**
* func()传入resolve和reject,
* resolve()和reject()方法在外部调用,这里需要用bind修正一下this指向
* new 对象实例时,自动执行func()
*/
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
// 生成实例时(执行resolve和reject),如果报错,就把错误信息传入给reject()方法,并且直接执行reject()方法
this.reject(error)
}
}
resolve(result) { // result为成功态时接收的终值
// 只能由pedning状态 => fulfilled状态 (避免调用多次resolve reject)
if (this.PromiseState === myPromise.PENDING) {
/**
* 为什么resolve和reject要加setTimeout?
* 2.2.4规范 onFulfilled 和 onRejected 只允许在 execution context 栈仅包含平台代码时运行.
* 注1 这里的平台代码指的是引擎、环境以及 promise 的实施代码。实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。
* 这个事件队列可以采用“宏任务(macro-task)”机制,比如setTimeout 或者 setImmediate; 也可以采用“微任务(micro-task)”机制来实现, 比如 MutationObserver 或者process.nextTick。
*/
setTimeout(() => {
this.PromiseState = myPromise.FULFILLED;
this.PromiseResult = result;
/**
* 在执行resolve或者reject的时候,遍历自身的callbacks数组,
* 看看数组里面有没有then那边 保留 过来的 待执行函数,
* 然后逐个执行数组里面的函数,执行的时候会传入相应的参数
*/
this.onFulfilledCallbacks.forEach(callback => {
callback(result)
})
});
}
}
reject(reason) { // reason为拒绝态时接收的终值
// 只能由pedning状态 => rejected状态 (避免调用多次resolve reject)
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.REJECTED;
this.PromiseResult = reason;
this.onRejectedCallbacks.forEach(callback => {
callback(reason)
})
});
}
}
/**
* [注册fulfilled状态/rejected状态对应的回调函数]
* @param {function} onFulfilled fulfilled状态时 执行的函数
* @param {function} onRejected rejected状态时 执行的函数
* @returns {function} newPromsie 返回一个新的promise对象
*/
then(onFulfilled, onRejected) {
/**
* 参数校验:Promise规定then方法里面的两个参数如果不是函数的话就要被忽略
* 所谓“忽略”并不是什么都不干,
* 对于onFulfilled来说“忽略”就是将value原封不动的返回,
* 对于onRejected来说就是返回reason,
* onRejected因为是错误分支,我们返回reason应该throw一个Error
*/
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason;
};
// 2.2.7规范 then 方法必须返回一个 promise 对象
let promise2 = new myPromise((resolve, reject) => {
if (this.PromiseState === myPromise.FULFILLED) {
/**
* 为什么这里要加定时器setTimeout?
* 2.2.4规范 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用 注1
* 这里的平台代码指的是引擎、环境以及 promise 的实施代码。
* 实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。
* 这个事件队列可以采用“宏任务(macro-task)”机制,比如setTimeout 或者 setImmediate; 也可以采用“微任务(micro-task)”机制来实现, 比如 MutationObserver 或者process.nextTick。
*/
setTimeout(() => {
try {
// 2.2.7.1规范 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x),即运行resolvePromise()
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
// 2.2.7.2 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
reject(e); // 捕获前面onFulfilled中抛出的异常
}
});
} else if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
} else if (this.PromiseState === myPromise.PENDING) {
// pending 状态保存的 resolve() 和 reject() 回调也要符合 2.2.7.1 和 2.2.7.2 规范
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
})
return promise2
}
}
/**
* 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
* @param {promise} promise2 promise1.then方法返回的新的promise对象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
function resolvePromise(promise2, x, resolve, reject) {
// 2.3.1规范 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 2.3.2规范 如果 x 为 Promise ,则使 promise2 接受 x 的状态
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
/**
* 2.3.2.1 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
* 注意"直至 x 被执行或拒绝"这句话,
* 这句话的意思是:x 被执行x,如果执行的时候拿到一个y,还要继续解析y
*/
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
} else if (x.PromiseState === myPromise.FULFILLED) {
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
} else if (x.PromiseState === myPromise.REJECTED) {
// 2.3.2.3 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 2.3.3 如果 x 为对象或函数
try {
// 2.3.3.1 把 x.then 赋值给 then
var then = x.then;
} catch (e) {
// 2.3.3.2 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(e);
}
/**
* 2.3.3.3
* 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
* 传递两个回调函数作为参数,
* 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
*/
if (typeof then === 'function') {
// 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false; // 避免多次调用
try {
then.call(
x,
// 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
// 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r => {
if (called) return;
called = true;
reject(r);
}
)
} catch (e) {
/**
* 2.3.3.3.4 如果调用 then 方法抛出了异常 e
* 2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
*/
if (called) return;
called = true;
/**
* 2.3.3.3.4.2 否则以 e 为据因拒绝 promise
*/
reject(e);
}
} else {
// 2.3.3.4 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
return resolve(x);
}
}
// 清爽简洁 无注释版
class myPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func) {
this.PromiseState = myPromise.PENDING;
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
try {
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(result) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.FULFILLED;
this.PromiseResult = result;
this.onFulfilledCallbacks.forEach(callback => {
callback(result)
})
});
}
}
reject(reason) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.REJECTED;
this.PromiseResult = reason;
this.onRejectedCallbacks.forEach(callback => {
callback(reason)
})
});
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason;
};
let promise2 = new myPromise((resolve, reject) => {
if (this.PromiseState === myPromise.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
} else if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
} else if (this.PromiseState === myPromise.PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
} else if (x.PromiseState === myPromise.FULFILLED) {
resolve(x.PromiseResult);
} else if (x.PromiseState === myPromise.REJECTED) {
reject(x.PromiseResult);
}
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
try {
var then = x.then;
} catch (e) {
return reject(e);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(
x,
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
)
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
} else {
return resolve(x);
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/F-Han/OES.git
git@gitee.com:F-Han/OES.git
F-Han
OES
线上考试系统
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385