JavaScript 手写实现 promise 的某一个方法

基于现有的 Promise Api 实现 Promise 的某一个功能,我们一起来看下具体怎么实现吧~

Promise.resolve

  1. Promise.resolve = function (val) {
  2. return new Promise(resolve => resolve(val));
  3. };
  4. // test
  5. const p1 = new Promise(resolve => {
  6. setTimeout(() => void resolve('success'), 0);
  7. });
  8. const p2 = new Promise((_, reject) => {
  9. setTimeout(() => void reject('error'), 0);
  10. });
  11. Promise.resolve(p1).then(console.log); // success
  12. Promise.resolve(p2).catch(console.log); // error
  13. Promise.resolve(2).then(console.log); // 2
  14. Promise.resolve('string').then(console.log); // string
  15. Promise.resolve(null).then(console.log); // null
  16. Promise.resolve(undefined).then(console.log); // undefined
  17. Promise.resolve(true).then(console.log); // true
  18. Promise.resolve(false).then(console.log); // false
JavaScript

Promise.reject

  1. Promise.reject = function (val) {
  2. return new Promise((_, reject) => reject(val));
  3. };
  4. // test
  5. const p1 = Promise.resolve('success');
  6. Promise.reject(p1).catch(console.log); // Promise { 'success' }
  7. Promise.reject(2).catch(console.log); // 2
  8. Promise.reject('string').catch(console.log); // string
  9. Promise.reject(null).catch(console.log); // null
  10. Promise.reject(undefined).catch(console.log); // undefined
  11. Promise.reject(true).catch(console.log); // true
  12. Promise.reject(false).catch(console.log); // false
JavaScript

Promise.prototype.catch

  1. /**
  2. * 基于现有的Promise Api,实现promise.prototype.cache
  3. *
  4. * cache 其实是一个特殊的then,只是第一个参数为null
  5. * @param {*} func 回调函数
  6. * @returns
  7. */
  8. Promise.prototype.catch = function (func) {
  9. return new Promise(resolve => {
  10. this.then(null, err => {
  11. // 这里要注意一下,回调函数执行结果要传给下一个promise
  12. resolve(func(err));
  13. });
  14. });
  15. };
  16. // test
  17. Promise.reject('error test')
  18. .catch(err => {
  19. console.log(err);
  20. return 'catch';
  21. })
  22. .then(console.log);
  23. // error test
  24. // catch
JavaScript

Promise.prototype.finally

  1. /**
  2. * 基于现有的Promise Api,实现promise.prototype.finally
  3. *
  4. * 注意事项:
  5. * (1)回调函数不接收参数
  6. * (2)回调函数的执行结果不传递给下一个Promise
  7. * @param {*} func 回调函数
  8. * @returns
  9. */
  10. Promise.prototype.finally = function (func) {
  11. return new Promise((resolve, reject) => {
  12. this.then(res => {
  13. func();
  14. resolve(res);
  15. }).catch(err => {
  16. func();
  17. reject(err);
  18. });
  19. });
  20. };
  21. // test
  22. Promise.resolve('success')
  23. .then(() => 'then')
  24. .finally(() => {
  25. console.log('finally');
  26. return 'finally';
  27. })
  28. .then(console.log);
  29. // finally
  30. // then
  31. // 通过上面的打印结果我们可以看到,finally函数返回的字符串 'finally' 并没有打印出来,
  32. // 打印出来的字符串 'then' 是由finally的前一个then函数返回的
  33. // 这也符合我们的预期《回调函数的执行结果不传递给下一个Promise》
  34. Promise.reject('reject')
  35. .catch(() => 'catch')
  36. .finally(() => {
  37. console.log('finally');
  38. return 'finally';
  39. })
  40. .then(console.log);
  41. // finally
  42. // catch
  43. // 通过上面的打印结果我们可以看到,finally函数返回的字符串 'finally' 并没有打印出来,
  44. // 打印出来的字符串 'catch' 是由finally的前一个catch函数返回的
  45. // 这也符合我们的预期《回调函数的执行结果不传递给下一个Promise》
JavaScript

Promise.all

  1. /**
  2. * 基于现有的Promise Api,实现promise.all
  3. * @param {*} args
  4. * @returns
  5. */
  6. Promise.all = function (args) {
  7. const getType = obj =>
  8. Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  9. // 判断传进来的参数是否可枚举
  10. if (args[Symbol.iterator]) {
  11. const arr = Array.from(args);
  12. if (arr.length === 0) return Promise.resolve([]);
  13. // 用来记录每一个promise成功后返回的数据
  14. const ans = new Array(arr.length);
  15. // 当前已经执行成功的Promise的数目
  16. let count = 0;
  17. // 返回一个新的Promise对象
  18. return new Promise((resolve, reject) => {
  19. arr.forEach((promise, index) => {
  20. if (getType(promise) !== 'promise') {
  21. // 如果数组的某一项不是一个Promise,将其包装成Promise
  22. promise = Promise.resolve(promise);
  23. }
  24. promise
  25. .then(res => {
  26. ans[index] = res;
  27. count++;
  28. if (count === arr.length) {
  29. // 如果所有的Promise都执行成功了,返回数据
  30. resolve(ans);
  31. }
  32. })
  33. .catch(reject); // 任何一个Promise失败了,直接返回失败的结果
  34. });
  35. });
  36. }
  37. };
  38. // test
  39. Promise.all([Promise.resolve(1), Promise.resolve(2)]).then(console.log); // [1,2]
  40. Promise.all([3, Promise.resolve(4)]).then(console.log); // [3,4]
  41. Promise.all([5, 6]).then(console.log); // [5,6]
JavaScript

Promise.any

  1. Promise.any = function (args) {
  2. if (args[Symbol.iterator]) {
  3. const getType = obj =>
  4. Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  5. let count = 0;
  6. const errors = Array(args.length);
  7. return new Promise((resolve, reject) => {
  8. args.forEach((promise, index) => {
  9. if (getType(promise) !== 'promise') {
  10. promise = Promise.resolve(promise);
  11. }
  12. promise.then(resolve).catch(err => {
  13. errors[index] = err;
  14. count++;
  15. if (count === args.length) {
  16. reject(new AggregateError(errors, 'All promises were rejected'));
  17. }
  18. });
  19. });
  20. });
  21. }
  22. };
  23. // test
  24. const p1 = Promise.reject('err1');
  25. const p2 = Promise.reject('err2');
  26. const p3 = Promise.resolve('success');
  27. Promise.any([1, 2, 3]).then(console.log).catch(console.log); // 1
  28. Promise.any([p1, p2, p3]).then(console.log).catch(console.log); // success
  29. Promise.any([p1, p2]).then(console.log).catch(console.log);
  30. // AggregateError: All promises were rejected
  31. // at xxx.js {
  32. // [errors]: [ 'err1', 'err2' ]
  33. // }
JavaScript

Promise.race

  1. const getType = obj =>
  2. Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  3. const isPromise = obj => getType(obj) === 'promise';
  4. Promise.race = function (args) {
  5. if (args[Symbol.iterator]) {
  6. const arr = Array.from(args);
  7. return new Promise((resolve, reject) => {
  8. arr.forEach(promise => {
  9. if (!isPromise(promise)) {
  10. promise = Promise.resolve(promise);
  11. }
  12. // 因为Promise的状态只能改变一次,所以我们多次调用resolve和reject
  13. // 只有第一次调用的时候才生效
  14. promise.then(resolve).catch(reject);
  15. });
  16. });
  17. }
  18. };
  19. // test
  20. const p1 = Promise.resolve(1);
  21. const p2 = Promise.reject(2);
  22. Promise.race([p1, p2]).then(console.log).catch(console.log); // 1
  23. Promise.race([p2, p1]).then(console.log).catch(console.log); // 1
  24. Promise.race([3, p1]).then(console.log).catch(console.log); // 3
  25. Promise.race([4, 5]).then(console.log).catch(console.log); // 4
JavaScript

Promise.allSettled

  1. Promise.allSettled = function (args) {
  2. if (args[Symbol.iterator]) {
  3. const res = Array(args.length);
  4. let count = 0;
  5. const getType = obj =>
  6. Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  7. return new Promise(resolve => {
  8. args.forEach((promise, index) => {
  9. if (getType(promise) !== 'promise') {
  10. promise = Promise.resolve(promise);
  11. }
  12. promise
  13. .then(value => {
  14. res[index] = { status: 'fulfilled', value };
  15. })
  16. .catch(reason => {
  17. res[index] = { status: 'rejected', reason };
  18. })
  19. .finally(() => {
  20. count++;
  21. if (count === args.length) {
  22. resolve(res);
  23. }
  24. });
  25. });
  26. });
  27. }
  28. };
  29. // test
  30. const p1 = Promise.reject('err1');
  31. const p2 = Promise.reject('err2');
  32. const p3 = Promise.resolve('success');
  33. Promise.allSettled([p1, p2, p3]).then(res => console.log(res));
  34. // [
  35. // { status: 'rejected', reason: 'err1' },
  36. // { status: 'rejected', reason: 'err2' },
  37. // { status: 'fulfilled', value: 'success' }
  38. // ]
  39. Promise.allSettled([1, 2, 3]).then(res => console.log(res));
  40. // [
  41. // { status: 'fulfilled', value: 1 },
  42. // { status: 'fulfilled', value: 2 },
  43. // { status: 'fulfilled', value: 3 }
  44. // ]
JavaScript
编程笔记 & 随笔杂谈