function* factorial(n) {
if(n===0) return 1;
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
yield result; // 每次产出 i! 的值
}
}
2025年11月12日大约 3 分钟
function* factorial(n) {
if(n===0) return 1;
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
yield result; // 每次产出 i! 的值
}
}
type F = () => Promise<any>
async function promisePool(functions: F[], n: number): Promise<any[]> {
// 利用数组自身的迭代器,减少变量的维护
const iterator = functions[Symbol.iterator]()
// 任务执行器,存在空闲,主动任务队列拿取新任务执行
async function worker() {
while (true) {
const { value: fn, done } = iterator.next()
if (done) break
await fn()
}
}
// 创建 n 个 worker,每个 worker 会连续取任务执行
const workers = Array.from({ length: n }, () => worker())
// 等待所有 worker 完成
return Promise.allSettled(workers)
}
/**
* const sleep = (t) => new Promise(res => setTimeout(res, t));
* promisePool([() => sleep(500), () => sleep(400)], 1)
* .then(console.log) // After 900ms
*/
使用 Proxy 和 Reflect 对象进行代理,拦截修改操作
type JSONValue =
| null
| boolean
| number
| string
| JSONValue[]
| { [key: string]: JSONValue }
type Obj = Array<JSONValue> | Record<string, JSONValue>
const METHODS = ['pop', 'push', 'shift', 'unshift', 'splice', 'sort', 'reverse']
const isObject = (obj: any) => typeof obj === 'object' && obj !== null
const proxyHandler: ProxyHandler<any> = {
get: (target, props) => {
// 获取当前访问属性
const val = Reflect.get(target, props)
// 非对象返回值
if (!isObject(val)) return val
// 递归代理
return proxify(val)
},
set: (target, props) => {
//直接修改数组,抛出异常
if (Array.isArray(target)) {
throw `Error Modifying Index: ${String(props)}`
}
// 抛出对象异常修改
throw `Error Modifying: ${String(props)}`
},
}
function makeImmutable(obj: Obj): any {
return proxify(obj)
}
const methodHandler: ProxyHandler<(...args: any[]) => any> = {
apply(target) {
throw `Error Calling Method: ${target.name}`
},
}
function proxify<T extends Obj>(obj: T): T {
if (Array.isArray(obj)) {
// 遍历拦截数组操作方法
METHODS.forEach((method: (typeof METHODS)[number]) => (
(obj as any)[method] = new Proxy((obj as any)[method], methodHandler)
// 直接重写也可以
// (obj as any)[method] = ()=> { throw `Error Calling Method: ${target.name}`}
)
}
return new Proxy(obj, proxyHandler) as T
}
interface Array<T> {
upperBound(target: number): number
}
/**
* 二分法
* 时间复杂度: O(log n)
* 空间复杂度: O(1) 没有使用额外空间
*/
Array.prototype.upperBound = function (target: number): number {
let left = 0, right = this.length - 1;
let result = -1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (this[mid] === target) {
result = mid;
left = mid + 1; // 向右查找更新更大的索引
} else if (this[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
/**
* 遍历
* 时间复杂度: O(n) 最坏情况下需要遍历整个字符串
* 空间复杂度: O(1) 没有使用额外空间
*/
Array.prototype.upperBound = function(target) {
for(let i = this.length - 1; i >= 0; i--) {
if(target === this[i]) return i
}
return -1;
};
/**
* 双指针遍历
* 时间复杂度 O(n)
* 空间复杂度 O(1)
*/
Array.prototype.upperBound = function (target): number {
if (this.length == 0) return -1
let i = 0
let l = this.length - 1
let upperIndex = -1
while (i <= l) {
if (this[l] === target) return l
if (this[i] > target) return upperIndex;
if (this[i] === target) {
if (i > upperIndex) upperIndex = i
}
i++;
l--;
}
return upperIndex;
}
/**
* js 数原生方法
* 时间复杂度: O(n) 最坏情况下需要遍历整个字符串
* 空间复杂度: O(1) 没有使用额外空间
*/
Array.prototype.upperBound = function(target) {
return this.lastIndexOf(target);
};
type FulfilledObj = {
status: 'fulfilled'
value: string
}
type RejectedObj = {
status: 'rejected'
reason: string
}
type Obj = FulfilledObj | RejectedObj
function promiseAllSettled(functions: Function[]): Promise<Obj[]> {
return new Promise((reslove) => {
const result = Array.from({ length: functions.length })
let endCount = 0
for (let i = 0; i < functions.length; i++) {
functions[i]()
.then((value: string) => (result[i] = { status: 'fulfilled', value }))
.catch((reason: string) => (result[i] = { status: 'rejected', reason }))
.finally(() => {
endCount += 1
if (endCount === functions.length) {
reslove(result as Obj[])
}
})
}
})
}
/**
* const functions = [
* () => new Promise(resolve => setTimeout(() => resolve(15), 100))
* ]
* const time = performance.now()
*
* const promise = promiseAllSettled(functions);
*
* promise.then(res => {
* const out = {t: Math.floor(performance.now() - time), values: res}
* console.log(out) // {"t":100,"values":[{"status":"fulfilled","value":15}]}
* })
*/
type CallbackFn = (
next: (data: number, error: string) => void,
...args: number[]
) => void
type Promisified = (...args: number[]) => Promise<number>
function promisify(fn: CallbackFn): Promisified {
return (...args) =>
new Promise((res, rej) => {
fn((data, err) => {
if (err) rej(err)
res(data)
}, ...args)
})
}
/**
* const asyncFunc = promisify(callback => callback(42));
* asyncFunc().then(console.log); // 42
*/
type Fn = () => Promise<any>
const delayAll = (functions, ms) => {
return functions.map(
(fn) => () =>
new Promise((resolve, reject) =>
setTimeout(() => {
fn().then(resolve).catch(reject)
}, ms)
)
)
}
function cancellable<T>(
generator: Generator<Promise<any>, T, unknown>
): [() => void, Promise<T>] {
let cancelled = false
const cancel = () => {
cancelled = true
}
const promise = new Promise<T>(async (resolve, reject) => {
try {
let result = generator.next()
while (!result.done) {
await result.value
if (cancelled) return reject('Cancelled')
result = generator.next()
}
if (cancelled) return reject('Cancelled')
resolve(result.value)
} catch (err) {
if (cancelled) return reject('Cancelled')
reject(err)
}
})
return [cancel, promise]
}
type IntervalFn = () => void
interface CustomIntervalMap {
[id: number]: boolean
}
// 用于存储每个定时器的“取消”状态
const intervalMap: CustomIntervalMap = {}
let uid = 0
/**
* 模拟 setInterval,支持 clear
* @param fn 执行的函数
* @param delay 首次延迟
* @param period 周期间隔
* @returns id 可用于 clear
*/
function customInterval(fn: IntervalFn, delay: number, period: number): number {
const id = ++uid
intervalMap[id] = false
let count = 0
const cb = () => {
if (intervalMap[id]) return // 被 clear 掉
fn()
setTimeout(cb, count++ * period + delay)
}
setTimeout(cb, count++ * period + delay)
return id
}
/**
* 清除定时器
* @param id 定时器 id
*/
function customClearInterval(id: number): void {
intervalMap[id] = true
}
function* dateRangeGenerator(
start: string,
end: string,
step: number
): Generator<string> {
const startTime = Date.parse(start)
const endTime = Date.parse(end)
if (isNaN(startTime) || isNaN(endTime)) {
throw new Error('Invalid start or end date')
}
if (step <= 0) {
throw new Error('Step must be greater than 0')
}
const ONE_DAY = 86400000 // 24 * 60 * 60 * 1000
const stepTime = step * ONE_DAY
for (let time = startTime; time <= endTime; time += stepTime) {
const d = new Date(time)
const y = d.getFullYear()
const m = (d.getMonth() + 1).toString().padStart(2, '0')
const day = d.getDate().toString().padStart(2, '0')
yield `${y}-${m}-${day}`
}
}
/**
* const g = dateRangeGenerator('2023-04-01', '2023-04-04', 1);
* g.next().value; // '2023-04-01'
* g.next().value; // '2023-04-02'
* g.next().value; // '2023-04-03'
* g.next().value; // '2023-04-04'
* g.next().done; // true
*/