js手写题

提取 url 参数,并转化为对象形式。

const url = "https://alibaba.com?a=1&b=2&c=3#hash";

function queryURLParams(URL) {
  const url = URL.split("?")[1];
  const urlSearchParams = new URLSearchParams(url);

  // const object = { x: 23, y:24 };
  // const entries = Object.entries(object); // [['x', 23], ['y', 24]]
  // const result = Object.fromEntries(entries); // { x: 23, y: 24 }
  const params = Object.fromEntries(urlSearchParams.entries());
  // const arr = [
  //   ["0", "a"],
  //   ["1", "b"],
  //   ["2", "c"],
  // ];
  // const obj = Object.fromEntries(arr);
  // console.log(obj); // { 0: "a", 1: "b", 2: "c" }
  return params;
}
console.log(queryURLParams(url));

数组扁平化

// 方法一
arr.flat(Infinity);

// 方法二
const flatten = function (arr) {
  return [].concat(...arr.map((v) => (Array.isArray(v) ? flatten(v) : v)));
};

const arr = [1, 2, [3, 4, [5, 6, [7, 8]], 9, 10, [11, 12, [13, 14]]]];
console.log(flatten(arr));

生成随机数组

// 方法一
function randomArr(arr) {
  // 范围:[0, 1)
  return arr.sort(() => Math.random() - 0.5);
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(randomArr(arr));

// 方法二
function sort(arr) {
  for (let i = 0; i < arr.length; i++) {
    const randomIndex = parseInt(Math.random() * arr.length); // 范围:[0, arr.length)
    [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
  }
  return arr;
}

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
sort(arr);

两数之和

// 两数之和
function twoSum(nums, target) {
  for (let i = 0; i < nums.length; i++) {
    const num = nums[i];
    const targetIndex = nums.indexOf(target - num);
    if (targetIndex > -1 && targetIndex !== i) {
      return [i, targetIndex];
    }
  }
}

const nums = [2, 7, 11, 15];
console.log(twoSum(nums, 9));

质数(只能被 1 和自身整除的数为质数)

判断一个数是不是质数(只能被 1 和自身整除的数为质数)

在一般领域,对正整数 n,如果用 2 到 根号 n 之间的所有整数去除,均无法整除,则 n 为质数。 质数大于等于 2 不能被它本身和 1 以外的数整除

// 判断一个数是不是质数(只能被1和自身整除的数为质数)
function isPrimeNumber(num) {
  if (num === 1) return false;
  if (num === 2) return true;
  for (let i = 2; i < Math.sqrt(num) + 1; i++) {
    if (num % i === 0) {
      // 在 [2, num) 中找到了可以被整除的数
      return false;
    }
  }
  return true;
}
console.log(isPrimeNumber(97));

打印 100 以内的所有质数

function printPrimeNum(num) {
  const isPrimeNumbers = [];
  for (let i = 2; i <= num; i++) {
    let isPrime = true;
    for (let j = i - 1; j > 1; j--) {
      if (i % j === 0) {
        // 不是素数
        isPrime = false;
        break;
      }
    }
    if (isPrime) {
      isPrimeNumbers.push(i);
    }
  }
  return isPrimeNumbers;
}

console.log(printPrimeNum(100));

数组去重

// 数组去重
const arr = [1, 2, 3, 5, 2, 4, 1, 3, 10, 6, 2];

// 方法一 new Set()
const distinct = (arr) => Array.from(new Set(arr));

// 方法二 filter + indexOf
const distinct = (arr) =>
  arr.filter((item, index, arr) => arr.indexOf(item) === index);

console.log(distinct(arr));

计算斐波那契数列

// 1, 2, 3, 5, 8, 13, 21, ....
// fn(n) = fn(n - 1) + fn(n - 2),fn(1) = 1,fn(2) = 2
function fibonacci(n) {
  // if (n === 1) return 1
  // if (n === 2) return 2
  if (n <= 2) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10));

计算阶乘

// n! = n * (n - 1)!
// n! = n * (n - 1) * ... * 3 * 2 * 1
// 1! = 1
function factorial(n) {
  // 返回的是n的阶乘
  if (n === 1) return 1;
  return n * factorial(n - 1);
}

console.log(factorial(9));

数组排序

1. 快速排序

利用二分法 + 递归的原理

function quickSort(arr) {
  // 退出递归的条件:数组中只剩下一个元素时 返回数组
  if (arr.length <= 1) return arr;

  const middleIndex = Math.floor(arr.length / 2);
  const middle = arr[middleIndex];

  const left = [];
  const right = [];
  const center = [];

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < middle) {
      left.push(arr[i]);
    } else if (arr[i] > middle) {
      right.push(arr[i]);
    } else {
      center.push(arr[i]);
    }
  }

  return quickSort(left).concat(center, quickSort(right));
}

const arr = [3, 1, 4, 9, 10, 1, 3, 2, 5, 9, 6];
console.log(quickSort(arr));

2. 插入排序

以下是插入排序的基本思想步骤:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤 2~5,直到所有元素均排序完毕。
function insertSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    let j = i - 1;
    const current = arr[i];
    // 必须使用变量将当前值保存起来,不然后面数组下标变化,导致出现问题。
    while (j >= 0 && arr[j] > current) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = current;
  }
  return arr;
}

const arr = [2, 1, 4, 3, 8, 9, 5, 7, 10, 2, 33];
console.log(insertSort(arr));

3. 冒泡排序

function bubbleSort(arr) {
  // 不易理解
  // for (let i = 0; i < arr.length - 1; i++) {
  //   for (let j = i + 1; j < arr.length; j++) {
  //     if (arr[i] > arr[j]) {
  //       [arr[i], arr[j]] = [arr[j], arr[i]]
  //     }
  //   }
  // }

  // 原数组:[4, 3, 2, 1]
  // [4, 3, 2, 1] i = 0, j = 0 --> [3, 4, 2, 1]
  //              i = 0, j = 1 --> [3, 2, 4, 1]
  //              i = 0, j = 2 --> [3, 2, 1, 4]
  // [3, 2, 1, 4] i = 1  j = 0, 1  --> [2, 3, 1, 4], [2, 1, 3, 4]
  // [2, 1, 3, 4] i = 2  j = 0  --> [1, 2, 3, 4]
  // [1, 2, 3, 4] i = 3         --> [1, 2, 3, 4]
  // 外层遍历控制行,内层遍历控制列
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

const arr = [2, 1, 4, 3, 8, 9, 5, 7, 10, 2, 33, 8];
console.log(bubbleSort(arr));

4. 选择排序

// 思想:查找最小值,记录索引。将未排序列最小值与已排序列的后一位进行交换。
function selectionSort(arr) {
  let minIndex;
  for (let i = 0; i < arr.length; i++) {
    minIndex = i;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j;
      }
    }
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
  }
  return arr;
}

const arr = [2, 1, 4, 3, 8, 9, 5, 7, 10, 2, 33, 8];
console.log(selectionSort(arr));

深拷贝、浅拷贝、赋值

1. 深拷贝

深拷贝

// 方法一
JSON.parse(JSON.stringify());

// 方法二(基础版本)
function deepClone(target, map = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (typeof target === "object") {
    // 对于引用数据类型,创建一个对象将所有字段依次添加到对象上并返回
    const obj = Array.isArray(target) ? [] : {};

    // 检查map中有无克隆过的对象
    // 有 - 直接返回
    // 没有 - 将当前对象作为key,克隆对象作为value进行存储
    // 继续克隆
    if (map.get(target)) {
      return map.get(target);
    }
    map.set(target, obj);
    for (const key in target) {
      obj[key] = deepClone(target[key], map);
    }
    return obj;
  } else {
    // 对于基本数据类型直接返回
    return target;
  }
}

2. 浅拷贝

浅拷贝

// 方法一
const obj = Object.assign({}, target);

// 方法二
const a = { ...obj };

// 方法三
Array.prototype.concat();
const arr2 = arr.concat();

// 方法三
Array.prototype.slice();
const arr3 = arr.slice();

防抖 debounce

短时间内多次触发同一事件,只会执行一次,非立即执行默认是执行最后一次。
如果设置了立即执行参数,则会立即执行一次,在规定时间内后面的都不触发。

应用

  • 每次 resize / scroll 触发统计事件
  • 文本输入的验证 (连续输入文字后发送AJAX请求进行验证,验证一次就好)
  • 输入请求后端接口进行补全的功能。

非立即执行基础版

function debounce(fun, delay = 500) {
  let timer = null;
  // 返回一个函数
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    // 开启定时器
    timer = setTimeout(() => {
      fun.apply(this, arguments);
      timer = null;
    }, delay);
  };
}

可以看到,为了记录定时器的值,采用闭包的原理,将 timer 的值保存在内存中。

立即执行基础版

function debounce(fun, delay = 500) {
  // 返回一个函数
  let timer = null;
  return function () {
    // 首先需要执行一次
    if (!timer) {
      fun.apply(this, arguments);
    } else {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      timer = null;
    }, delay);
  };
}

完整版本

把以上代码整合并优化后得到下面代码

对 this 的指向又优化了下,允许通过参数执行 this 值

export const debounce = (
  fun: Function,
  delay: number = 500,
  immediate: boolean = false
): Function => {
  let timer: any = null;
  return function (context: any, ...args: Array<any>) {
    if (timer) {
      clearTimeout(timer);
    } else {
      immediate && fun.apply(context, args);
    }
    timer = setTimeout(() => {
      if (!immediate) {
        fun.apply(context, args);
      } else {
        timer = null;
      }
    }, delay);
  };
};

测试demo

function fn1() {
  console.log('姓名:', this.name, '年龄:', this.age, '这是立即执行函数');
}
function fn2() {
  console.log('姓名:', this.name, '年龄:', this.age, '这是非立即执行函数');
}

const obj = {
  name: 'ps',
  age: 18,
  say1: debounce(fn1, 500, true),
  say2: debounce(fn2, 500, false)
}

for (let i = 0; i < 100; i++) {
  setTimeout(() => {
    obj.say1()
    obj.say2()
  }, 100)
}

节流 throttle

一段时间内多次触发同一事件,会在这段时间内连续执行,
在 n 秒中只执行一次函数。即 2n 秒内执行 2 次… 。节流如字面意思,会稀释函数的执行频率。类似与滴水效果。

应用

  • 与mousemove keyup/keydown 等相密切联系的函数
  • 浏览器窗口变化时更新eharts等图表的函数。
  • 秒杀、抢卷按钮,按下一次后,接下来几秒不让用户继续按(也可用锁实现)

非立即执行基础版

function throttle(func, delay = 500) {
  let timer = null;
  return function () {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        func.apply(this, arguments);
      }, delay);
    }
  };
}

立即执行基础版

function throttle(fun, delay = 500) {
  let timer = null;
  return function () {
    if (!timer) {
      fun.apply(this, arguments)
      timer = setTimeout(() => {
        timer = null
      }, delay)
    }
  };
}

完整版本

function throttle(fun, delay = 500, immediate = false) {
  let timer = null;
  return function () {
    if (!timer) {
      immediate && fun.apply(this, arguments);
      timer = setTimeout(() => {
        timer = null
        !immediate && fun.apply(this, arguments);
      }, delay);
    }
  };
}

测试demo

function fn1(num) {
  console.log('姓名:', this.name, '年龄:', this.age, '数字是:', num, '这是立即执行');
}

function fn2(num) {
  console.log('姓名:', this.name, '年龄:', this.age, '数字是:', num, '这是非立即执行');
}

const obj = {
  name: 'ps',
  age: 18,
  say1: throttle(fn1, 500, true),
  say2: throttle(fn2)
}
let num = 0
const timer = setInterval(() => {
  if (num === 100) {
    clearInterval(timer)
  }
  num++
  obj.say1(num)
  obj.say2(num)
}, 100)

把类数组转换为数组

//通过Array.from方法来实现转换
Array.from(arrayLike)

// 通过扩展运算符
[...arrayLike]

//通过call调用数组的slice方法来实现转换
Array.prototype.slice.call(arrayLike)

//通过call调用数组的splice方法来实现转换
Array.prototype.splice.call(arrayLike,0)

//通过apply调用数组的concat方法来实现转换
Array.prototype.concat.apply([],arrayLike)

括号匹配

const str1 = "{[]}"; // true
const str2 = "{[[]}"; // false
const str3 = "{[]}["; // false
const str4 = "{[()]}"; // true
function isValid(str) {
  if (str.length % 2 !== 0) return false;
  const stack = [];
  const map = {
    ")": "(",
    "]": "[",
    "}": "{",
  };
  for (const s of str) {
    if (s === "{" || s === "[" || s === "(") {
      // 只要是 {、[、( 就入栈
      stack.push(s);
    } else {
      // 遇到 }、]、) 就匹配出栈
      if (stack.pop() !== map[s]) return false;
    }
  }
  if (stack.length === 0) return true;
}

console.log(isValid(str1));
console.log(isValid(str2));
console.log(isValid(str3));
console.log(isValid(str4));

翻转字符串

// 方法一
function reverseString(str) {
  return str.split("").reverse().join("");
}

// 方法二
function reverseString(str) {
  let result = "";
  const len = str.length;
  for (let i = len - 1; i >= 0; i--) {
    result += str[i];
  }
  return result;
}

const str = "hello world !";
console.log(reverseString(str));

生成随机 16 进制颜色

// 方法一 padStart, 补全字符串
function randomHexColor() {
  // [0, 256) 向下取整后为 [0, 255)
  const red = Math.floor(Math.random() * 256)
    .toString(16)
    .padStart(2, "0");
  const green = Math.floor(Math.random() * 256)
    .toString(16)
    .padStart(2, "0");
  const blue = Math.floor(Math.random() * 256)
    .toString(16)
    .padStart(2, "0");
  return `#${red}${green}${blue}`;
}

// 方法二
function randomHexColor() {
  return `#${Math.random().toString(16).substring(2, 8)}`;
}

// 方法三
function randomHexColor() {
  const red = Math.floor(Math.random() * 256);
  const green = Math.floor(Math.random() * 256);
  const blue = Math.floor(Math.random() * 256);
  const opacity = Math.random().toFixed(2);
  return `rgba(${red}, ${green}, ${blue}, ${opacity})`;
}

console.log(randomHexColor());

获取指定范围内的随机整数

Math.floor; // 向下取整
Math.ceil; // 向上取整
Math.round; // 四舍五入

function rangeRandomNum(min, max) {
  // [min, max]
  return Math.round(Math.random() * (max - min)) + min;
  // [min, max)
  return Math.floor(Math.random() * (max - min)) + min;
  // (min, max]
  return Math.ceil(Math.random() * (max - min)) + min;
  // (min, max)
  return Math.round(Math.random() * (max - min - 2)) + min + 1;
}

console.log(rangeRandomNum(3, 9));

实现 call、apply、bind

Function.prototype.myCall = function (context, ...args) {
  // 1. 判断调用myCall的是否为函数
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.myCall - 调用myCall的对象必须是函数!"
    );
  }

  // 如果没有传入上下文对象,则默认为全局对象
  // ES11 引入了 globalThis,它是一个统一的全局对象 (window对象)
  context = context || globalThis;

  // 用Symbol来创建唯一的一个function,防止命名冲突。
  const fn = Symbol();

  // this 是调用myCall的函数,将函数绑定到上下文对象的新属性上
  context[fn] = this;

  // 传入myCall的多个参数
  const result = context[fn](...args);
  console.log(context);

  // 将增加在上下文对象上的fn方法删除
  delete context.fn;

  return result;
};
Function.prototype.myApply = function (context, args = []) {
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.myApply - 调用myApply的对象必须是函数!"
    );
  }

  if (!Array.isArray(args)) {
    throw new TypeError("Function.prototype.myApply - 第二个参数必须为数组!");
  }

  context = context || globalThis;

  const fn = Symbol();

  context[fn] = this;

  const result = context[fn](...args);

  delete context.fn;

  return result;
};
Function.prototype.myBind = function (context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError(
      "Function.prototype.myBind - 调用myBind的对象必须是函数!"
    );
  }

  // 将要被调用的函数用常量保存起来
  const _this = this;

  // 返回一个匿名函数
  return function () {
    const fn = Symbol();

    context[fn] = _this;

    // 整合参数并执行
    const result = context[fn](...args, ...arguments);

    delete context[fn];

    return result;
  };
};

实现 new

function myNew(constructor, ...args) {
  // 创建一个空对象
  const obj = {};
  // 改变 obj 的原型
  obj.__proto__ = constructor.prototype;
  // 使用 obj 来调用构造函数,并传入参数。
  const result = constructor.apply(obj, args);
  // 构造函数如果有返回值,返回值为引用数据类型,直接返回
  // 构造函数如果没有返回值,返回 obj
  return typeof result === "object" ? result : obj;
}

const p2 = myNew(Person, "ps2", 16);

实现发布订阅模式(EventEmitter)、观察者模式(Observer)

// 参考文章
// https://juejin.cn/post/7052637219084828680
class Observer {
  constructor() {
    this.events = {};
  }
  on(type, handler) {
    if (!this.events[type]) {
      this.events[type] = [];
    }
    this.events[type].push(handler);
  }
  once(type, handler) {
    const onceCallback = (data) => {
      handler(data); // 执行回调函数
      this.off(type, onceCallback);
    };
    this.on(type, onceCallback);
  }
  // 一、只有 type 删除整个type事件
  // 二、存在 handler 只删除里面有 handler 的
  off(type, handler) {
    if (!this.events[type]) return;
    if (!handler) {
      delete this.events[type];
    } else {
      this.events[type] = this.events[type].filter((cb) => cb !== handler);
    }
  }
  emit(type, params) {
    if (!this.events[type]) return;
    this.events[type].forEach((handler) => {
      handler(params);
    });
  }
}

const ob = new Observer();
function handlerA(data) {
  console.log("getList", data);
}
function handlerB(data) {
  console.log("getData", data);
}
ob.on("getListA", handlerA);
ob.on("getListA", handlerB);
ob.on("getData", handlerB);
// ob.off('getData')
// ob.off('getListA', handlerA)
ob.emit("getListA", "这是测试数据A");
ob.emit("getData", "这是测试数据B");
console.log(ob);

实现 Promise

1. 基础版

class MyPromise {
  // 定义三种状态
  static PENGING = "pending";
  static FULFILLED = "fulfilled";
  static REJECT = "reject";

  constructor(executor) {
    // 初始化状态
    this.status = MyPromise.PENGING;
    // 初始化值
    this.value = null;
    this.reason = null;
    // 成功的回调队列
    this.onFulfilledCallback = [];
    // 失败的回调队列
    this.onRejectedCallback = [];
    // 执行并绑定this
    executor(this.reslove.bind(this), this.reject.bind(this));
  }

  reslove(value) {
    // 状态一旦变更就不会再发生变化。
    if (this.status !== MyPromise.PENGING) return;
    this.value = value;
    this.status = MyPromise.FULFILLED;
    this.onFulfilledCallback.length && this.onFulfilledCallback.shift()();
  }

  reject(reason) {
    // 状态一旦变更就不会再发生变化。
    if (this.status !== MyPromise.PENGING) return;
    this.reason = reason;
    this.status = MyPromise.REJECT;
    this.onRejectedCallback.length && this.onRejectedCallback.shift()();
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled !== "function" ? () => {} : onFulfilled;
    onRejected = typeof onRejected !== "function" ? () => {} : onRejected;
    return new MyPromise(() => {
      if (this.status === MyPromise.PENGING) {
        this.onFulfilledCallback.push(() =>
          setTimeout(() => onFulfilled(this.value))
        );
        this.onRejectedCallback.push(() =>
          setTimeout(() => onRejected(this.reason))
        );
      } else if (this.status === MyPromise.FULFILLED) {
        onFulfilled(this.value);
      } else if (this.status === MyPromise.REJECT) {
        onRejected(this.reason);
      }
    });
  }
}

const p1 = new MyPromise((resolve, reject) => {
  resolve("p1成功");
  console.log("p1-console");
  setTimeout(() => {
    resolve("p1成功-setTimeout");
    reject("p1-失败-setTimeout");
    console.log("p1-console-setTimeout");
  }, 100);
});

p1.then(
  (value) => {
    console.log("value: ", value);
  },
  (reason) => {
    console.log("reason: ", reason);
  }
);

2. 实现 all 函数

成功的时候返回一个成功的数组;失败的时候则返回最先被 reject 失败状态的值。

static all(list) {
  return new MyPromise((resolve, reject) => {
    const result = []
    let count = 0
    for (let i = 0; i < list.length; i++) {
      const p = list[i]
      p.then(value => {
        result[i] = value
        count += 1
        if (count === list.length) {
          resolve(result)
        }
      }, reason => {
        reject(reason)
      })
    }
  })
}

3. 实现 race 函数

只要有一个完成,不管成功还是失败,都返回

static race(list) {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < list.length; i++) {
      const p = list[i]
      p.then(value => {
        resolve(value)
      }, reason => {
        reject(reason)
      })
    }
  })
}

完整代码

class MyPromise {
  // 定义三种状态
  static PENGING = "pending";
  static FULFILLED = "fulfilled";
  static REJECT = "reject";

  constructor(executor) {
    // 初始化状态
    this.status = MyPromise.PENGING;
    // 初始化值
    this.value = null;
    this.reason = null;
    // 成功的回调队列
    this.onFulfilledCallback = [];
    // 失败的回调队列
    this.onRejectedCallback = [];
    // 执行并绑定this
    executor(this.reslove.bind(this), this.reject.bind(this));
  }

  reslove(value) {
    // 状态一旦变更就不会再发生变化。
    if (this.status !== MyPromise.PENGING) return;
    this.value = value;
    this.status = MyPromise.FULFILLED;
    this.onFulfilledCallback.length && this.onFulfilledCallback.shift()();
  }

  reject(reason) {
    // 状态一旦变更就不会再发生变化。
    if (this.status !== MyPromise.PENGING) return;
    this.reason = reason;
    this.status = MyPromise.REJECT;
    this.onRejectedCallback.length && this.onRejectedCallback.shift()();
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled !== "function" ? () => {} : onFulfilled;
    onRejected = typeof onRejected !== "function" ? () => {} : onRejected;
    return new MyPromise(() => {
      if (this.status === MyPromise.PENGING) {
        this.onFulfilledCallback.push(() =>
          setTimeout(() => onFulfilled(this.value))
        );
        this.onRejectedCallback.push(() =>
          setTimeout(() => onRejected(this.reason))
        );
      } else if (this.status === MyPromise.FULFILLED) {
        onFulfilled(this.value);
      } else if (this.status === MyPromise.REJECT) {
        onRejected(this.reason);
      }
    });
  }

  // 成功的时候返回一个成功的数组;失败的时候则返回最先被reject失败状态的值。
  static all(list) {
    return new MyPromise((resolve, reject) => {
      const result = [];
      let count = 0;
      for (let i = 0; i < list.length; i++) {
        const p = list[i];
        p.then(
          (value) => {
            result[i] = value;
            count += 1;
            if (count === list.length) {
              resolve(result);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }

  static race(list) {
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < list.length; i++) {
        const p = list[i];
        p.then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
}

const p1 = new MyPromise((resolve, reject) => {
  // resolve('p1成功');
  // console.log('p1-console');
  setTimeout(() => {
    resolve("p1成功-setTimeout");
    reject("p1-失败-setTimeout");
    console.log("p1-console-setTimeout");
  }, 100);
});
const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2成功");
    // reject('p2失败')
  }, 200);
});
const p3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("p3成功");
  }, 30);
});
// MyPromise.all([p1, p2, p3]).then(res => {
//   console.log('all-成功', res);
// }, reason => {
//   console.log('all-失败', reason)
// })
MyPromise.race([p1, p2, p3]).then(
  (res) => {
    console.log("race-成功", res);
  },
  (reason) => {
    console.log("race-失败", reason);
  }
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值