控制并发请求的函数
/**
*
* @param {string[]} urls url数组
* @param {number} max 最大并发数
*/
function concurrentRequests(urls: string[], max = 6) { //chrome最大并发请求6个
return new Promise((resolve) => {
if (urls.length === 0) {
resolve([]);
return;
}
const urlLen = urls.length;
const results = [];
// 下一个请求
let next = 0;
// 请求完成数量
let finished = 0;
async function _request() {
// 超过urls个数,就停止
if (next === urlLen) {
return;
}
const i = next;
const url = urls[i];
next++;
try {
const res = await fetch(url);
results[i] = res;
} catch (err) {
results[i] = err;
} finally {
finished++;
// 所有请求完成就执行resolve()
if (finished === urlLen) {
resolve(results);
}
//成功或失败都调用下一个请求
//不去等待响应结果可以看做同时发
_request();
}
}
//最大并发数如果大于url个数,取最小数
const times = Math.min(max, urlLen);
for (let i = 0; i < times; i++) {
_request();
}
});
}
深拷贝
function isObject(value) {
const valueType = typeof value
return (value !== null) && (valueType === "object" || valueType === "function")
}
function deepClone(originValue, map = new WeakMap()) {
// Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 函数
if (typeof originValue === "function") {
return originValue
}
// 不是对象
if (!isObject(originValue)) {
return originValue
}
//防止循环应用
if (map.has(originValue)) {
return map.get(originValue)
}
// 判断传入的对象是数组, 还是对象
const newObject = Array.isArray(originValue) ? []: {}
map.set(originValue, newObject)
for (const key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
newObject[sKey] = deepClone(originValue[sKey], map)
}
return newObject
}
防抖
function debounce(fn, delay) {
let timer = null;
const _debounce = function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
};
return _debounce;
}
加上this和参数
function debounce(fn, delay) {
let timer = null
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
// this绑定为_debounce的this
fn.apply(this, args)
}, delay)
}
return _debounce
}
加上立即执行
function debounce(fn, delay, immediate = false) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args)
isInvoke = false
}, delay)
}
}
return _debounce
}
加上取消功能
function debounce(fn, delay, immediate = false) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args)
isInvoke = false
timer = null
}, delay)
}
}
// 封装取消功能
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
获取返回值,两种方式获取返回值,promise或者回调函数
function debounce(fn, delay, immediate = false, resultCallback) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
return new Promise((resolve, reject) => {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
const result = fn.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
isInvoke = true
} else {
timer = setTimeout(() => {
const result = fn.apply(this, args)
if (resultCallback) resultCallback(result)
resolve(result)
isInvoke = false
timer = null
}, delay)
}
})
}
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
节流
function throttle(fn, interval) {
let lastTime = Date.now()
const _throttle = function () {
const nowTime = Date.now()
if (nowTime - lastTime >= interval) {
lastTime = Date.now()
return fn.apply(this, [...arguments])
}
}
return _throttle
}
instanceof
function myInstanceof(left, right) {
if (typeof left !== 'object' || typeof left !== 'function' || left === null) {
return false
}
let proto = Object.getPrototypeOf(left)
while (true) {
if (proto === null) return false
if (proto === right.prototype) return true
proto = Object.getPrototypeOf(proto)
}
}
typeof
function myTypeof(obj) {
const type = typeof obj
if (type !== 'object') {
return type
}
return Object.prototype.toString.call(obj).replace(/^[object (\S+)]$/,'$1')
call
Function.prototype.myCall = function (ctx, ...args) {
// ctx保证是对象
ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx);
const fn = this;
// 避免覆盖
const key = Symbol("fn");
// 不能枚举
Object.defineProperty(ctx, key, {
value: fn,
enumerable: false,
});
const res = ctx[key](...args);
delete ctx[key];
return res;
};
apply
Function.prototype.myApply = function (context, args) {
if (typeof this !== "function") {
console.error("type error");
}
if (args && !(args instanceof Array)) {
console.error("type error");
return;
}
context = context ?? window;
context = Object(context);
const fn = Symbol();
context[fn] = this;
let res;
if (args) {
res = context[fn](...args);
} else {
res = context[fn]();
}
delete context[fn];
return res;
};
bind
Function.prototype.myBind = function (context, ...args) {
if (typeof this !== "function") {
console.error("type eeeor");
}
const fn = this;
return function Fn(...paras) {
return fn.apply(this instanceof Fn ? this : context, args.concat(paras));
};
};
new
function myNew(Func, ...args) {
const obj = Object.create(Func.prototype)
const result = Func.apply(obj, args)
return result instanceof Object ? result : obj
}
Promise
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
// 处理错误
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return //防止resolve 和 reject 一起执行
this.value = value
this.status = PROMISE_STATUS_FULFILLED
this.onFulfilledFns.forEach(fn => fn(this.value))
})
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.reason = reason
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach(fn => fn(this.reason))
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
}
实现then方法
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
this.onFulfilledFns.push(() =>
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
)
this.onRejectedFns.push(() =>
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
)
})
}
实现catch方法
catch(onRejected) {
this.then(undefined, onRejected)
}
实现finally
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
实现 resolve和reject
static resolve(value) {
return new MyPromise((resolve) => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
Promise.all
Promise.myAll = function (proms) {
let res;
let rej;
const p = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
let result = [];
//promise数量
let count = 0;
// promise完成数量
let finished = 0;
for (const prom of proms) {
//保证promise返回结果的顺序
const i = count;
count++;
//保证传的数组里面是promise
// Promise.resolve(prom)传入一个promise,那它返回的promise的状态由传入的这个promise决定
Promise.resolve(prom).then((data) => {
// 汇总数据
result[i] = data;
// 判断是否全部执行完
finished++;
if (finished === count) {
res(result);
}
}, rej);
}
if (count === 0) {
res(result);
}
return p;
};
柯里化
// es6
function curry(fn, ...args) {
return fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);
}
数组map
Array.prototype._map = function (exec) {
if (typeof exec !== "function") {
throw TypeError("need function");
}
const newArr = [];
for (let i = 0; i < this.length; i++) {
newArr[i] = exec(this[i], i, this);
}
return newArr;
};
数组filter
Array.prototype._filter = function (exec) {
if (typeof exec !== "function") {
throw TypeError("need function");
}
const newArr = [];
for (let i = 0; i < this.length; i++) {
if (exec(this[i], i, this)) {
newArr.push(this[i]);
}
}
return newArr;
};
数组reduce
Reduce 每一步都将当前元素的值与前一步的结果相加(该结果是之前所有步骤结果的总和)——直到没有更多需要相加的元素
Array.prototype._reduce = function (exec, initialVal) {
if (typeof exec !== "function") {
throw TypeError("need function");
}
for (let i = initialVal ? 0 : 1; i < this.length; i++) {
initialVal = exec(initialVal ?? this[0], this[i], i, this);
}
return initialVal;
};