Javascript基础

118 阅读5分钟

promise并发

如果需要请求100个接口,但是由于浏览器限制,只能请求几个,这时候考虑并发问题。

promise.all()

这个方法会等待所有请求完成后一次性返回结果。那么可以将100个请求进行分组,比如5个一组。在上一组返回后再请求下一组

promise.race()

这个方法会在第一个promise请求成功或失败时直接返回结果

第三方库

例如async.js和p-limit

手动实现

        const arr = [];
        for (let i = 0; i < 100; i++) {
            arr.push(() => new Promise((resolve) => {
                setTimeout(() => {
                    console.log('done', i);
                    resolve();
                }, 100 * i);
            }));
        };

        const parallelRun = () => {
            const runingTask = new Map();
            const inqueue = (totalTask, max) => {
                while (runingTask.size < max && totalTask.length) {
                    const newTask = totalTask.shift();
                    const tempName = totalTask.length;
                    runingTask.set(tempName, newTask);
                    newTask().finally(() => {
                        runingTask.delete(tempName);
                        inqueue(totalTask, max);
                    });
                }
            }
            return inqueue;
        };

        parallelRun()(arr, 6);

函数

提前调用

普通函数提前调用不会报错,这是因为变量提升

但是通过const创建的箭头函数会报错

image.png

对象比较

首先可以分为浅比较和深比较

浅比较

function shallowEqual(object1, object2) {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);
  // 判断长度
  if (keys1.length !== keys2.length) {
    return false;
  }
  //逐个查找对比
  for (let key of keys1) {
    if (object1[key] !== object2[key]) {
      return false;
    }
  }

  return true;
}

深比较

深比较也就是递归比较

只要是object类型的key,就递归调用函数进行比较,否则直接使用!==比较。

function deepEqual(object1, object2) {
  const keys1 = Object.keys(object1);
  const keys2 = Object.keys(object2);

  if (keys1.length !== keys2.length) {
    return false;
  }

  for (const key of keys1) {
    const val1 = object1[key];
    const val2 = object2[key];
    const areObjects = isObject(val1) && isObject(val2);
    if (
      (areObjects && !deepEqual(val1, val2)) ||
      (!areObjects && val1 !== val2)
    ) {
      return false;
    }
  }

  return true;
}

function isObject(object) {
  return object != null && typeof object === "object";
}

事件循环

JS是单线程,所以分为异步和同步。

异步中又分为微任务和宏任务。

微任务

常见:promise.thenasync await

宏任务

常见:setTimeoutsetInterval

执行

异步队列中分为微任务队列和宏任务队列。

在所有同步任务执行完毕后,异步任务会优先执行已经在队列中的微任务,在所有微任务执行完毕后,再执行宏任务队列中的一个有且仅有一个)宏任务,执行完一个宏任务后检查是否有微任务,有则执行,无则执行下一个宏任务,以此循环。

字符串转数组

1.Array.from()

Array.from('string') // ['s','t','r','i','n','g']

2.String.prototype.split

const str = 'string'
const arr = str.split('') // ['s','t','r','i','n','g']

快速创建一个从0到100的数组

Array.from(Array(101).keys())

promise

promise.all与promise.allSettled

两者区别在于,all在任何一个输入的promise被拒绝时立即拒绝,且立即抛出错误。

而allSettled会等待所有的promise完成。

promise.all

promise.all([function,function]).then((resp)=>{
    //这里的resp是一个数组,包含两个异步函数的返回
    }
).catch()
async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice(),
    fetchPrices(),
  ]);
  return prices[choice];
}

all会返回一个数组,结果的顺序只跟all接收顺序有关。

reject 回调执行是,只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误

promise.allSettled

原型链

每个函数都有一个prototype属性,在这个属性上可以挂载函数或者属性。

例如,有一个Person()函数,那么就有Person.prototype,这个Person.prototype就是Person()的原型对象。同时这个原型对象有一个constructor属性,又指向这个函数。同时new出来的实例,可以直接调用原型对象(Person.prototype)上面挂载的方法或属性。

image.png

例如ES6当中Set()函数,在这个函数的prototype(原型对象)上面挂载了很多方法,这些方法可以对set实例进行操作。例如add函数,就是挂载到Set.prototype上面的方法。

const set = new Set()
set.add('name','cjq')

try catch

这是同步代码块,不能捕获异步代码的错误。

正确做法是在异步代码块里面使用trycatch

判断类型

1.typeof

能判断基本数据类型和function。但是不能判断null,会返回object。

复杂数据类型都返回object。

2.instanceof

该方法是沿着原型链寻找类型。

不能检测基本数据类型。

原型链可能被修改导致结果不准确。

只要能在原型链上找到构造函数就会返回true,所以结果不准确。

1 instanceof Number //true
[] instanceof Array //true
[] instanceof Object //true

3.Object.prototype.toString.call() 推荐

返回值是[object Object]字符串

const arr = [1, 2, 3];
arr.toString(); // "1,2,3"
Object.prototype.toString.call(arr); // "[object Array]"

4.Array.isArray()

判断是否为数组

Array.isArray('[]') // false

ES6中Set

Set去重使用的是 === (零和判断)

===的判断无法判断两个不同引用地址的对象相等。

new Set(arr)会将数组转为一个set对象,此时需要用Array.from转换为数组

注意 无法对对象进行去重

原因我不是很清楚,MDN中没有明确写出原因。

我猜测是因为对象存储在栈中的只是一个地址,即使堆中的对象空间里的数据是相同的,但是地址不同,此时会判定两个对象不同,所以不会去重。

image.png

const为什么能修改对象或数组

首先,需要理解JS中栈和堆的概念。

在JS数据结构中,栈存储基本数据类型以及复杂数据类型(引用数据类型)的地址(指针)。而复杂数据类型的内容都存储在堆中。

const定义变量时,会让存储在栈中的东西无法修改。

所以const只能保证指针不发生变化。