/** * 手动实现promise的功能, 只能保证功能相同。用于来更加深刻的理解promise * 为什么这里要用一个立即执行函数,因为这里没有用模块化,所以用立即执行函数,防止定义的名字相同,导致全局污染 * @type {{new(): MyPromise, prototype: MyPromise}} */ const MyPromise = (() => { // 定义一些常量 const PENDING = "pending", // 等待状态(未决状态) RESOLVE = "resolved", // 成功状态 (已决状态) REJECT = "rejected", // 失败状态 (已决状态) thenables = Symbol("用于保存成功状态的队列"), // catchables = Symbol("用来保存失败状态的队列"), // promiseStatus = Symbol("PromiseStatus"), // 用符号来保存promise的状态,防止外部访问 promiseValue = Symbol("PromiseValue"), // promise的值 changeStatus = Symbol("改变状态的函数"), execSettledCommon = Symbol("执行已决状态的公共方法"), createPromise = Symbol("用于创建一个新的promise,用于then或者catch方法后的链式调用"); return class MyPromise { /** * 一进来创建promise实例是传入两个方法,一个是resolve, 一个是reject * @param executor */ constructor(executor) { // 创建promise实例后的状态是pending,值是undefined this[promiseStatus] = PENDING; this[promiseValue] = undefined; this[thenables] = []; //后续处理函数的数组 -> resolved this[catchables] = []; //后续处理函数的数组 -> rejected // 成功的状态 已决 const resolve = (data) => { this[changeStatus](RESOLVE, data, this[thenables]); }; // 失败的状态 已决 const reject = (err) => { this[changeStatus](REJECT, err, this[catchables]); }; // 这里的try catch 用于捕捉 promise里面抛出的错误,抛到上一层 try { executor(resolve, reject) } catch (err) { reject(err); } } /** * 改变promise状态的方法 * @param status 修改成对应的状态 * @param value 修改的值 * @param queue 修改状态的时候执行放入thenables 或者 catchables队列里面的函数 */ [changeStatus](status, value, queue) { // 因为promise的状态是单向传递的,不可逆转的,所以当只有状态为pending的时候才可以往往下走 if (this[promiseStatus] === PENDING) { this[promiseStatus] = status; this[promiseValue] = value; // 当状态改变的时候,执行then/catch队列里面的对应函数 queue.forEach(handler => handler(value)); } } /** * 执行已决状态的后续函数的公共方法 * @param handler 后续处理函数 * @param status 当前状态 * @param queue 如果当前状态是resolve或者reject, 放入对应的thenables 和 catchables的消息队列中 */ [execSettledCommon](handler, status, queue) { // 只有当传入的函数是一个函数的时候,才会去执行该函数 if (typeof handler !== "function") { return; } if (this[promiseStatus] === status) { // 用于模拟promise 是异步的,promise会放到微队列中执行 setTimeout(() => { handler(this[promiseValue]); }, 0); } else { // 否则放入消息队列 queue.push(handler); } } /** * 用于创建返回的promise的方法 * @param thenHandler then 后续函数 * @param catchHandler catch 后续函数 * @returns {MyPromise} */ [createPromise](thenHandler, catchHandler) { /** * 用于内部调用 执行then/catch 的后续函数的操作, 使得外部不能访问,只给内部使用 * @param data 调用传入的数据 * @param handler 传入的then 或者catch 函数 * @param resolve 成功的毁掉 * @param reject 失败的毁掉 */ function exec(data, handler, resolve, reject) { try { // 执行通过then函数来改变状态 const result = handler(data); // 这里需要判断result 返回的是不是一个promise对象,如果是promise对象,直接直接调用then(成功状态下),或者调用catch if (result instanceof MyPromise) { result.then(res => { resolve(res); }, err => { reject(err); }) } else { resolve(result); } } catch (e) { reject(e) } } return new MyPromise((resolve, reject) => { // 使用then一直链式调用 this[execSettledCommon](data => { exec(data, thenHandler, resolve, reject); }, RESOLVE, this[thenables]); // 使用catch一直链式调用 this[execSettledCommon](err => { exec(err, catchHandler, resolve, reject); }, REJECT, this[catchables]); }) } /** * 用于接收promise的状态, 也就是resolved状态,或者失败的rejected状态 * @param thenHandler 成功的处理函数 * @param catchHandler 失败的处理函数 */ then(thenHandler, catchHandler) { // 因为我们的then 函数或者catch函数放入createPromise 这里面处理了 // this[execSettledCommon](thenHandler, RESOLVE, this[thenables]); // // 如果在then里面传了catchHandler的函数,执行下面这个代码 // this.catch(catchHandler); return this[createPromise](thenHandler, catchHandler) }; /** * 用于接收promise失败的状态 * @param catchHandler 失败的处理函数 */ catch(catchHandler) { // this[execSettledCommon](catchHandler, REJECT, this[catchables]); return this[createPromise](undefined, catchHandler) }; /** * 当所有的promise代码全部完成, 就返回成功的集合,失败一个着返回全部失败 * @param proms promise 数组 * @returns {MyPromise} */ static all(proms) { return new MyPromise((resolve, reject) => { const promsArrs = proms.map(p => { const obj = { hasDone: false, resultData: undefined, }; p.then(res => { obj.hasDone = true; obj.resultData = res; // 判断promise数组里面的promise对象是否全部完全 const hasFinishArr = promsArrs.filter(item => !item.hasDone); if (hasFinishArr.length === 0) { // 代表所有的promise都已经完成 resolve(promsArrs); } }, err => { reject(err); }); return obj; }) }) } /** * 当所有的promise数组只要有一个成功 就返回成功,失败就返回失败 * @param proms promise 数组 * @returns {MyPromise} */ static race(proms) { return new MyPromise((resolve, reject) => { proms.forEach(p => { p.then(res => { resolve(res); }, err => { reject(err); }) }) }) } /** * promise成功的直接调用 * @param data 结果 * @returns {MyPromise} */ static resolve(data) { // 判断结果是不是一个promise对象 if (data instanceof MyPromise) { // 如果是promise对象,直接返回就好 return data; } else { // 不是promise对象,直接返回一个promise对象 return new MyPromise((resolve, reject) => { resolve(data); }) } } /** * promise的失败的直接调用 * @param err 错误的原因 错误原因直接返回一个promise对象,不会阻塞代码的执行 * @returns {MyPromise} */ static reject(err) { return new MyPromise((resolve, reject) => { reject(err) }) } } })();
使用方法
<script src="Promise.js"></script> <script> const pro = new MyPromise((resolve, reject) => { resolve(12323) }); pro.then(res => { console.log("第一次成功:结果是", res); return "第一次成功返回"; }, err => { console.log("第一次失败:结果是", err); throw "第一次失败返回" }).then(res => { console.log("第二次成功:结果是", res); return "第二次成功返回"; }, err => { console.log("第二次失败:结果是", err); throw "第二次失败返回" }).then(res => { console.log("第三次成功:结果是", res); return "第三次成功返回"; }, err => { console.log("第三次失败:结果是", err); throw "第三次失败返回" }).then(res => { console.log("第四次成功:结果是", res); return "第四次成功返回"; }, err => { console.log("第四次失败:结果是", err); throw "第四次失败返回" }).catch(err => { console.log("最后的失败结果:", err); }) // const pro1 = new Promise((resolve, reject) => { // resolve(1) // }); // pro1.then(res => { // console.log(res); // }) // console.log(2343244) </script>
结果: