学习链接
BAT前端经典面试问题:史上最最最详细的手写Promise教程(代码来源,其他链接是为了当收藏家(
手把手一行一行代码教你“手写Promise“,完美通过 Promises/A+ 官方872个测试用例
Promise
class Promise {constructor(executor) {this.state = 'pending';this.value = undefined;this.reason = undefined;this.onResolvedCallback = [];this.onRejectedCallback = [];const resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;this.onResolvedCallback.forEach(fn => fn());}};const reject = reason => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.onRejectedCallback.forEach(fn => fn());}};try {executor(resolve, reject);} catch (err) {reject(err);}}then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };const promise2 = new Promise((resolve, reject) => {if (this.state === 'fulfilled') {queueMicrotask(() => {try {let result = onFulfilled(this.value);resolvePromise(promise2, result, resolve, reject);} catch (error) {reject(error);}});}if (this.state === 'rejected') {queueMicrotask(() => {try {let result = onRejected(this.reason);resolvePromise(promise2, result, resolve, reject);} catch (error) {reject(error);}});}if (this.state === 'pending') {this.onResolvedCallback.push(() => {queueMicrotask(() => {try {let result = onFulfilled(this.value);resolvePromise(promise2, result, resolve, reject);} catch (error) {reject(error);}});});this.onRejectedCallback.push(() => {queueMicrotask(() => {try {let result = onRejected(this.reason);resolvePromise(promise2, result, resolve, reject);} catch (error) {reject(error);}});});}})return promise2; // 完成链式调用}}function resolvePromise(promise2, result, resolve, reject) {// resolve 和 reject 是 promise2 实例构建时候的参数方法// result 是then方法参数中传入的回调函数 的返回结果if (result === promise2) {return reject(new TypeError('Chaining cycle detected for promise'));}// 防止 resolve reject 被多次调用(catch)let called = false;if (result === null || (typeof result !== 'object' && typeof result !== 'function')) {return resolve(result);}try {let then = result.then;if (typeof then !== 'function') {return resolve(result);}then.call(result, value => {if (called) return;called = true;resolvePromise(promise2, value, resolve, reject);}, reason => {if (called) return;called = true;reject(reason);})} catch (error) {if (called) return;called = true;reject(error);}}Promise.resolve = function (value) {return new Promise((resolve, reject) => {resolve(value);});}Promise.reject = function (reason) {return new Promise((resolve, reject) => {reject(reason);});}Promise.all = promiseArr => {return new Promise((resolve, reject) => {if (!promiseArr[Symbol.iterator]) {throw new TypeError(`${promiseArr} is not iterable`) // 需要iterator接口}if (!Array.isArray(promiseArr)) {promiseArr = Array.from(promiseArr); // 根据 iterator 接口转为数组}let result = [], count = 0; // count 记录fulfilled数量promiseArr.forEach((p, i) => {Promise.resolve(p).then(res => { // 转为 Promise 对象count++; // 进入then的回调, fulfilled的实例数加一result[i] = res;if (count === promiseArr.length) {resolve(result);}}, err => {reject(err);})})})}Promise.any = promiseArr => {return new Promise((resolve, reject) => {if (!promiseArr[Symbol.iterator]) {throw new TypeError(`${promiseArr}is not iterable`);}if (!Array.isArray(promiseArr)) {promiseArr = Array.from(promiseArr);}const result = [];let count = 0;promiseArr.forEach((p, i) => {Promise.resolve(p).then(value => {resolve(value);},reason => {count++;result[i] = reason;if (count === promiseArr.length) {reject(new AggregateError(result, 'All Promises were rejected'));}})});})}Promise.race = promiseArr => {return new Promise((resolve, reject) => {if (!promiseArr[Symbol.iterator]) {throw new TypeError(`${promiseArr} is not iterable`);}if (!Array.isArray(promiseArr)) {Array.from(promiseArr);}promiseArr.forEach(element => {Promise.resolve(element).then(resolve, reject);});});};Promise.allSettled = promiseArr => {return new Promise((resolve, reject) => {if (!promiseArr[Symbol.iterator]) {throw new TypeError(`${promiseArr} is not iterable`);}if (!Array.isArray(promiseArr)) {promiseArr = Array.from(promiseArr);}const resArr = [];let count = 0;promiseArr.forEach((element, index) => {Promise.resolve(element).then(valule => {resArr[index] = {status: 'fulfilled',valule}count++;if (count === promiseArr.length) resolve(resArr);},reason => {resArr[index] = {status: 'rejected',reason}count++;if (count === promiseArr.length) resolve(resArr);});});})};Promise.prototype.finally = callback => {return this.then(value => Promise.resolve(callback()).then(() => value),reason => Promise.resolve(callback()).then(() => { throw reason; }))};
