JS代码你能手撕多少

304 阅读2分钟

1.实现promise.all方法

promise.all方法接受一个Promise可迭代协议的参数, 只返回一个Promise实例, 返回的成功的结果resolve回调的结果是一个数组;等所有的promise,resolve都有结果后返回;只要任何一个promise的reject执行回调;就立即抛出错误,并且抛出是第一个reject的信息结果。

第一种方式:

Promise.prototype.all = function(arr) {
  const strings = Object.Prototype.toString;
  if(!arr || !arr.length || strings.call(arr) !== '[object Array]') {
    throw new TypeError('promise must be an Array');
  }
  const resArr = [];// 保存resolve结果
  for(let i = 0; i < arr.length; i++) {
    const p = arr[i];
    p.then(res => {
      resArr[i] = res; // 按顺序保存到数组里
    }).catch(e => {
      return Promise.reject(e); //有失败就返回失败信息 不再往后执行
    })
  }
  
  // 2.如果全部promise都成功回调 返回结果 []
  return Promise.resolve(resArr);
}

第二种:

Promise.ptototype.all = function(promises) {
  if(promises.constructor !== Array) {
    throw new TypeError('arguments must be an Array')
  }
  let count = 0;
  const resArr = [];
  return new Promise(function(resolve, reject){
    promises.forEach((p, i) => {
      p.then(res => {
        count++;
        resArr[i] = res; // 保存到数组里
        // 当promise成功的索引等于传递长度时就调用成功函数
        count === promises.length && resolve(resArr);
      }, e => {
        reject(e); // 执行失败
      })
    })
  })
}

2.手撕Promise.race方法

MDN文档

Promise.race方法接受可迭代对象, 例如Array

一旦迭代器中promise有的结果,就返回第一个promise的resolve或reject

迭代器为空就返回 promise 将永远等待。

Promise.prototype.race = function(promises) {
  if(!promises || !promises.length) {
    return new Promise(); // 返回永久等待。
  }
  
  return new Promise((resolve, reject) => {
    promises.forEach((p) => {
      p.then(resolve, reject); // 谁先返回就调用谁。
    })
  })
}

防抖和节流?

防抖函数(debounce)

短时间内多次触发同一事件,只触发最后一次,或者只执行最开始的一次,中间的不执行

非立即执行(执行最后一次)

// 非立即执行
// 接受两个参数 fn 函数体, wait 时间
function debounce(fn, wait) {
  // 定时器变量 
  let timer = null;
  return function() {
    let that = this; 
    let args = arguments; // 保存执行传递进来的参数
    if(timer) clearTimeout(timer)// 在执行中就清空
    timer = setTimeout(function() {
      fn.call(that, ...args); // this指向调用的函数
    }, wait)
  }
}

立即执行(执行开始一次)

function debounce(fn, wait) {
  let timer = null;
  return function() {
    const args = arguments;
    const that = this;
    
    const now = !timer; // 当没有定时器的时候就执行
    
    setTimeout(_ => timer = null, wait); // 执行到了就清空
    
    if(now) {
      fn.call(that, ...args);
    }
  }
}

节流函数(throttle)

在同一时间里面执行函数,再次触发不会被中断,直到执行完成后才可以执行下一次函数。

/**
* 定时器版本
*/

function throttle(fn, wait) {
  let timer = null;
  return function() {
    const args = arguments
    const that = this;
    if(timer) return; // 还在执行返回
    timer = setTimeout(function() {
      fn.call(that, ...args);
      clearTimeout(timer); // 执行完成清理定时器
    },wait)
  }
}

时间戳版本

function throttle(fn, wait) {
  let now = 0;
  return function() {
    const args = arguments;
    const that = this;
    
    const _newDate = Date.now();
    
    if(newDate - now > wait) {
      fn.call(that, ...args);
      now = _newDate;
    }
  }
}