深拷贝
fucntion deepClone(value) {
const cache = new WeakMap();
fucntion _deepClone(value) {
if(typeof value !== 'object' || value === null) {
return value;
}
if(cache.has(value)) {
return cache.get(value);
}
const result = Array.isArray(value) ? [] : {};
Object.setPrototypeOf(result, Object.getPrototypeOf(value));
cache.set(value, result);
for(let key in value) {
if(value.hasOwnProperty(key)) {
result[key] = _deepClone(value[key]);
}
}
return result;
}
return _deepClone(value);
}
fucntion deepClone(value) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel();
port1.postMessage(value);
port2.onmessage = (e) => {
resolve(e.data);
}
})
}
并发任务控制
class ControlTask() {
constructor(parallelCount = 2) {
this.parallelCount = parallelCount;
this.tasks = [];
this.runningNum = 0;
}
add(task) {
return new Promise((resolve, reject) => {
this.tasks.push({
task,
resolve,
reject
});
this.run();
})
}
run() {
if(this.runningNum < this.parallelCount && this.tasks.length) {
const { task, resolve, reject } = this.tasks.shift();
this.runningNum++;
Promise.resolev(task()).then(resolve, reject).finally(() => {
this.runningNum--;
this.run();
});
}
}
}
function timeout(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
const superTask = new SuperTask();
function addTask(time, name) {
superTask
.add(() => timeout(time))
.then(() => {
console.log(`任务${name}完成`)
})
}
addTask(1000, 1);
addTask(1000, 2);
addTask(1000, 3);
addTask(1000, 4);
addTask(1000, 5);
高量级任务优化
function runTask(task, callback) {
requestIdleCalback((idle) => {
if(idle.timeRemaining() > 0) {
task();
callback();
}else {
runTask(task, callback);
}
})
let start = Date.now();
requestAnimationFrame(() => {
if(Date.now - start < 16.6) {
task();
callback();
}else {
runTask(task, callback);
}
});
}
发布订阅模式
class EventEmitter {
constructor() {
this.events = {};
}
on(type, callBack) {
if (!this.events[type]) {
this.events[type] = [callBack];
} else {
this.events[type].push(callBack);
}
}
off(type, callBack) {
if (!this.events[type]) return;
this.events[type] = this.events[type].filter((item) => {
return item !== callBack;
});
}
once(type, callBack) {
function fn() {
callBack();
this.off(type, fn);
}
this.on(type, fn);
}
emit(type, ...rest) {
this.events[type] &&
this.events[type].forEach((fn) => fn.apply(this, rest));
}
}
flat方法递归实现
function flat(arr, depth = 1) {
return arr.reduce((result, item) => {
if (item === undefined || item === null) {
return result;
}
if (Array.isArray(item)) {
return result.concat(flat(item, depth - 1));
}
return result.concat(item);
}, []);
}
提取URL中的query参数
let url = 'xxxx';
const str = url.slice(url.indexOf('?'));
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
手写简易Promise
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function runMicroTask(callback) {
if (process && process.nextTick) {
process.nextTick(callback);
} else if (MutationObserver) {
const observer = new MutationObserver(callback);
const textNode = document.createTextNode("1");
observer.observe(textNode, {
childList: true,
});
textNode.data = "2";
} else {
setTimeout(callback, 0);
}
}
function isPromise(obj) {
return !!(obj && typeof obj === "object" && typeof obj.then === "function");
}
class MyPromise {
constructor(executor) {
this._state = PENDING;
this._value = undefined;
this._handlers = [];
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
}
}
_pushHandler(executor, state, resolve, reject) {
this._handlers.push({
executor,
state,
resolve,
reject,
});
}
_runHandlers() {
if (this._state === PENDING) {
return;
}
while (this._handlers[0]) {
this._runOneHandler(this._handlers[0]);
this._handlers.shift();
}
}
_runOneHandler({ executor, state, resolve, reject }) {
runMicroTask(() => {
if (this._state !== state) {
return;
}
if (typeof executor !== "function") {
this._state === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value);
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
});
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers();
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onSettled) {
return this.then(
(data) => {
onSettled();
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
}
_changeState(newState, value) {
if (this._state !== PENDING) {
return;
}
this._state = newState;
this._value = value;
this._runHandlers();
}
_resolve(data) {
this._changeState(FULFILLED, data);
}
_reject(reason) {
this._changeState(REJECTED, reason);
}
static resolve(data) {
if (data instanceof MyPromise) {
return data;
}
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
static all(proms) {
return new MyPromise((resolve, reject) => {
try {
const results = [];
let count = 0;
let fulfilledCount = 0;
for (const promise of proms) {
let i = count;
count++;
MyPromise.resolve(promise).then((data) => {
fulfilledCount++;
results[i] = data;
if (fulfilledCount === count) {
resolve(results);
}
}, reject);
}
if (count === 0) {
resolve(results);
}
} catch (error) {
reject(error);
}
});
}
static allSettled(proms) {
const ps = [];
for (const p of proms) {
ps.push(
MyPromise.resolve(p).then(
(value) => ({
status: FULFILLED,
value,
}),
(reason) => ({
status: FULFILLED,
reason,
})
)
);
}
return MyPromise.all(ps);
}
static race(proms) {
return MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then(resolve, reject);
}
});
}
}
const promise = new MyPromise((resolve, reject) => {
resolve(123);
});
console.log(promise);