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创建的箭头函数会报错
对象比较
首先可以分为浅比较和深比较
浅比较
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.then、async await
宏任务
常见:setTimeout、setInterval
执行
异步队列中分为微任务队列和宏任务队列。
在所有同步任务执行完毕后,异步任务会优先执行已经在队列中的微任务,在所有微任务执行完毕后,再执行宏任务队列中的一个(有且仅有一个)宏任务,执行完一个宏任务后检查是否有微任务,有则执行,无则执行下一个宏任务,以此循环。
字符串转数组
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)上面挂载的方法或属性。

例如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中没有明确写出原因。
我猜测是因为对象存储在栈中的只是一个地址,即使堆中的对象空间里的数据是相同的,但是地址不同,此时会判定两个对象不同,所以不会去重。

const为什么能修改对象或数组
首先,需要理解JS中栈和堆的概念。
在JS数据结构中,栈存储基本数据类型以及复杂数据类型(引用数据类型)的地址(指针)。而复杂数据类型的内容都存储在堆中。
const定义变量时,会让存储在栈中的东西无法修改。
所以const只能保证指针不发生变化。