JavaScript 手写实现 promise 的某一个方法
基于现有的 Promise Api 实现 Promise 的某一个功能,我们一起来看下具体怎么实现吧~
Promise.resolve
- Promise.resolve = function (val) {
- return new Promise(resolve => resolve(val));
- };
- // test
- const p1 = new Promise(resolve => {
- setTimeout(() => void resolve('success'), 0);
- });
- const p2 = new Promise((_, reject) => {
- setTimeout(() => void reject('error'), 0);
- });
- Promise.resolve(p1).then(console.log); // success
- Promise.resolve(p2).catch(console.log); // error
- Promise.resolve(2).then(console.log); // 2
- Promise.resolve('string').then(console.log); // string
- Promise.resolve(null).then(console.log); // null
- Promise.resolve(undefined).then(console.log); // undefined
- Promise.resolve(true).then(console.log); // true
- Promise.resolve(false).then(console.log); // false
JavaScript
Promise.reject
- Promise.reject = function (val) {
- return new Promise((_, reject) => reject(val));
- };
- // test
- const p1 = Promise.resolve('success');
- Promise.reject(p1).catch(console.log); // Promise { 'success' }
- Promise.reject(2).catch(console.log); // 2
- Promise.reject('string').catch(console.log); // string
- Promise.reject(null).catch(console.log); // null
- Promise.reject(undefined).catch(console.log); // undefined
- Promise.reject(true).catch(console.log); // true
- Promise.reject(false).catch(console.log); // false
JavaScript
Promise.prototype.catch
- /**
- * 基于现有的Promise Api,实现promise.prototype.cache
- *
- * cache 其实是一个特殊的then,只是第一个参数为null
- * @param {*} func 回调函数
- * @returns
- */
- Promise.prototype.catch = function (func) {
- return new Promise(resolve => {
- this.then(null, err => {
- // 这里要注意一下,回调函数执行结果要传给下一个promise
- resolve(func(err));
- });
- });
- };
- // test
- Promise.reject('error test')
- .catch(err => {
- console.log(err);
- return 'catch';
- })
- .then(console.log);
- // error test
- // catch
JavaScript
Promise.prototype.finally
- /**
- * 基于现有的Promise Api,实现promise.prototype.finally
- *
- * 注意事项:
- * (1)回调函数不接收参数
- * (2)回调函数的执行结果不传递给下一个Promise
- * @param {*} func 回调函数
- * @returns
- */
- Promise.prototype.finally = function (func) {
- return new Promise((resolve, reject) => {
- this.then(res => {
- func();
- resolve(res);
- }).catch(err => {
- func();
- reject(err);
- });
- });
- };
- // test
- Promise.resolve('success')
- .then(() => 'then')
- .finally(() => {
- console.log('finally');
- return 'finally';
- })
- .then(console.log);
- // finally
- // then
- // 通过上面的打印结果我们可以看到,finally函数返回的字符串 'finally' 并没有打印出来,
- // 打印出来的字符串 'then' 是由finally的前一个then函数返回的
- // 这也符合我们的预期《回调函数的执行结果不传递给下一个Promise》
- Promise.reject('reject')
- .catch(() => 'catch')
- .finally(() => {
- console.log('finally');
- return 'finally';
- })
- .then(console.log);
- // finally
- // catch
- // 通过上面的打印结果我们可以看到,finally函数返回的字符串 'finally' 并没有打印出来,
- // 打印出来的字符串 'catch' 是由finally的前一个catch函数返回的
- // 这也符合我们的预期《回调函数的执行结果不传递给下一个Promise》
JavaScript
Promise.all
- /**
- * 基于现有的Promise Api,实现promise.all
- * @param {*} args
- * @returns
- */
- Promise.all = function (args) {
- const getType = obj =>
- Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
- // 判断传进来的参数是否可枚举
- if (args[Symbol.iterator]) {
- const arr = Array.from(args);
- if (arr.length === 0) return Promise.resolve([]);
- // 用来记录每一个promise成功后返回的数据
- const ans = new Array(arr.length);
- // 当前已经执行成功的Promise的数目
- let count = 0;
- // 返回一个新的Promise对象
- return new Promise((resolve, reject) => {
- arr.forEach((promise, index) => {
- if (getType(promise) !== 'promise') {
- // 如果数组的某一项不是一个Promise,将其包装成Promise
- promise = Promise.resolve(promise);
- }
- promise
- .then(res => {
- ans[index] = res;
- count++;
- if (count === arr.length) {
- // 如果所有的Promise都执行成功了,返回数据
- resolve(ans);
- }
- })
- .catch(reject); // 任何一个Promise失败了,直接返回失败的结果
- });
- });
- }
- };
- // test
- Promise.all([Promise.resolve(1), Promise.resolve(2)]).then(console.log); // [1,2]
- Promise.all([3, Promise.resolve(4)]).then(console.log); // [3,4]
- Promise.all([5, 6]).then(console.log); // [5,6]
JavaScript
Promise.any
- Promise.any = function (args) {
- if (args[Symbol.iterator]) {
- const getType = obj =>
- Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
- let count = 0;
- const errors = Array(args.length);
- return new Promise((resolve, reject) => {
- args.forEach((promise, index) => {
- if (getType(promise) !== 'promise') {
- promise = Promise.resolve(promise);
- }
- promise.then(resolve).catch(err => {
- errors[index] = err;
- count++;
- if (count === args.length) {
- reject(new AggregateError(errors, 'All promises were rejected'));
- }
- });
- });
- });
- }
- };
- // test
- const p1 = Promise.reject('err1');
- const p2 = Promise.reject('err2');
- const p3 = Promise.resolve('success');
- Promise.any([1, 2, 3]).then(console.log).catch(console.log); // 1
- Promise.any([p1, p2, p3]).then(console.log).catch(console.log); // success
- Promise.any([p1, p2]).then(console.log).catch(console.log);
- // AggregateError: All promises were rejected
- // at xxx.js {
- // [errors]: [ 'err1', 'err2' ]
- // }
JavaScript
Promise.race
- const getType = obj =>
- Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
- const isPromise = obj => getType(obj) === 'promise';
- Promise.race = function (args) {
- if (args[Symbol.iterator]) {
- const arr = Array.from(args);
- return new Promise((resolve, reject) => {
- arr.forEach(promise => {
- if (!isPromise(promise)) {
- promise = Promise.resolve(promise);
- }
- // 因为Promise的状态只能改变一次,所以我们多次调用resolve和reject
- // 只有第一次调用的时候才生效
- promise.then(resolve).catch(reject);
- });
- });
- }
- };
- // test
- const p1 = Promise.resolve(1);
- const p2 = Promise.reject(2);
- Promise.race([p1, p2]).then(console.log).catch(console.log); // 1
- Promise.race([p2, p1]).then(console.log).catch(console.log); // 1
- Promise.race([3, p1]).then(console.log).catch(console.log); // 3
- Promise.race([4, 5]).then(console.log).catch(console.log); // 4
JavaScript
Promise.allSettled
- Promise.allSettled = function (args) {
- if (args[Symbol.iterator]) {
- const res = Array(args.length);
- let count = 0;
- const getType = obj =>
- Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
- return new Promise(resolve => {
- args.forEach((promise, index) => {
- if (getType(promise) !== 'promise') {
- promise = Promise.resolve(promise);
- }
- promise
- .then(value => {
- res[index] = { status: 'fulfilled', value };
- })
- .catch(reason => {
- res[index] = { status: 'rejected', reason };
- })
- .finally(() => {
- count++;
- if (count === args.length) {
- resolve(res);
- }
- });
- });
- });
- }
- };
- // test
- const p1 = Promise.reject('err1');
- const p2 = Promise.reject('err2');
- const p3 = Promise.resolve('success');
- Promise.allSettled([p1, p2, p3]).then(res => console.log(res));
- // [
- // { status: 'rejected', reason: 'err1' },
- // { status: 'rejected', reason: 'err2' },
- // { status: 'fulfilled', value: 'success' }
- // ]
- Promise.allSettled([1, 2, 3]).then(res => console.log(res));
- // [
- // { status: 'fulfilled', value: 1 },
- // { status: 'fulfilled', value: 2 },
- // { status: 'fulfilled', value: 3 }
- // ]
JavaScript