手撕题
使用useState/useRef 实现useCallback
function customUseCallback(cb, deps) {
const cbRef = React.useRef();
const [cbMemo, setCbMemo] = React.useState(cb);
React.useEffect(() => {
cbRef.current = cb;
setCbMemo((...args) => cbRef.current(...args));
}, [deps]);
return cbMemo;
}
Promise相关
Promise
class MyPromise {
constructor(excutor) {
this.resolveQueue = [];
this.rejectQueue = [];
let resolve = (value) => {
if (this.status === "pending") {
// 清理队列,设置状态,设置value
this.value = value;
this.status = "fulfilled";
this.resolveQueue.forEach((cb) => cb(value));
}
};
let reject = (e) => {
if (this.status === "pending") {
this.error = e;
this.status = "rejected";
this.rejectQueue.forEach((cb) => cb(e));
}
};
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
}
}
then = (onFulfilled, onRejected) => {
let onFulfilledAdpt =
typeof onFulfilled !== "function" ? (v) => v : onFulfilled;
let onRejectedAdpt =
typeof onRejected !== "function"
? (e) => {
throw e;
}
: onRejected;
return new MyPromise((resolve, reject) => {
if (this.status === "pending") {
this.resolveQueue.push(onFulfilledAdpt);
this.rejectQueue.push(onRejectedAdpt);
}
if (this.status === "fulfilled") {
const thenReturn = onFulfilled(this.value);
resolve?.(thenReturn); //onFulfiled回调执行结果传给下一个then
}
if (this.status === "rejected") {
const errorReturn = onRejected(this.error);
reject(errorReturn);
}
});
};
}
Promise.all
const promiseAll = (promises) => {
return new Promise((resolve, reject) => {
const result = [];
const length = promises.length;
let resolveCnt = 0;
for (let i = 0; i < length; i++) {
Promise.resolve(promises[i])
.then((value) => {
result[i] = value;
if (resolveCnt++ === length) {
resolve(result);
}
})
.catch((e) => {
reject(e);
});
}
});
};
PromiseWithRetry
function promiseWithRetry(asyncFn, times, delayTimes) {
let currentTime = 0;
return new Promise((resolve, reject) => {
function run() {
if (currentTime++ === times) {
reject("失败");
}
return asyncFn()
.then(resolve)
.catch((e) => {
setTimeout(() => {
run();
}, delayTimes);
});
}
run();
});
}
一些变式题
- 实现一个lock,
class Lock {
constructor() {
this.resolveQueue = [];
this.status = "EMPTY";
}
wait() {
return new Promise((resolve) => {
if (this.status === "PENDING") {
// If the lock is busy, add the task to the queue
this.resolveQueue.push(resolve);
} else {
// If the lock is available, take it and set status to "PENDING"
this.status = "PENDING";
resolve();
}
});
}
notify() {
// Take the next task from the queue (if any) and run it
if (this.resolveQueue.length > 0) {
const nextTask = this.resolveQueue.shift();
nextTask(); // Notify the next task
} else {
// No tasks waiting, release the lock
this.status = "EMPTY";
}
}
}
// 参考用例:
const lock = new Lock();
// 异步获取数据任务,耗时2s,已mock返回
let cache;
const getInfoOrReturnCache = async () => {
// if (cache) return Promise.resolve(cache);
return new Promise((resolve) => {
console.log("获取异步数据");
setTimeout(() => {
cache = { system: "IOS" };
resolve(cache);
}, 2000);
});
};
// 模块执行代码
async function doTask(taskNumber) {
await lock.wait();
console.log("task:" + taskNumber);
const res = await getInfoOrReturnCache();
lock.notify();
console.log("task: " + taskNumber + " system: " + res.system);
}
// 模块调用
doTask(1);
doTask(2);
doTask(3);
doTask(4);
// 输出:
// task1
// 获取异步数据
// task: 1 system: IOS
// task2
// task: 2 system: IOS
// task3
// task: 3 system: IOS
// task4
// task: 4 system: IOS
QueryString
函数Curry化
实现一个add函数,达到以下的执行效果
add(2,3,4)=9
add(2)(3,4)=9
add(2)(3)(4)=9
add(2,3)(4)=9
function add(...args) {
let result = args.reduce((p, v) => p + v, 0);
function innerAdd(...innerArgs) {
return add(...innerArgs, result);
}
innerAdd.toString = () => {
return result;
};
return innerAdd;
}