手撕代码

  1. 实现 Promise.all

    1. 需要返回一个 promise
    2. 接收的参数是一个promise或者非promise值组成的数组,用Promise.resolve统一处理
    3. 当所有任务完成的时候resolve结果数组
    4. 当有一个reject的时候整个函数reject
    5. 边界情况:传入的为空数组
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    const promiseAll = (jobs) => {
    return new Promise((resolve, reject) => {
    if (!Array.isArray(jobs)) {
    reject(new Error('传入的参数不是数组'))
    }
    // 处理边界
    if (jobs.length === 0) {
    resolve([])
    }
    const result = []
    let count = 0
    for (let i = 0; i < jobs.length; i++) {
    Promise.resolve(jobs[i])
    .then(res => {
    // 保证答案顺序,如果是判断类型再push的话顺序会乱
    result[i] = res
    count++
    if (count === jobs.length) {
    resolve(result)
    }
    })
    .catch(e => {
    reject(e)
    })
    }
    })
    }
  2. 实现 Promise.race

    1. 需要返回一个 Promise
    2. 返回的 Promise 根据输入的数据的第一个敲定而敲定
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const promiseRace = (jobs) => {
    return new Promise((resolve, reject) => {
    if (!Array.isArray(jobs)) {
    return reject(new Error("参数不是数组"));
    }

    for (let job of jobs) {
    Promise.resolve(job)
    .then((res) => {
    resolve(res);
    })
    .catch((e) => {
    reject(e);
    });
    }
    });
    };
  3. 实现 Promise.any

  4. 返回一个 promise 对象

  5. 当任意一个promise敲定时,返回的promise对象敲定

  6. 当可迭代参数里所有的都被拒绝时,返回的promise对象拒绝并返回一个错误数组

  7. 当传入空数组时拒绝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const promiseAny = (jobs) => {
return new Promise((resolve, reject) => {
if (!Array.isArray(jobs)) {
return reject(new Error("参数不是数组"));
}

// 边界情况
if (jobs.length === 0) {
return reject(new Error("All promises were rejected"));
}

let reasons = []
let count = 0
for (let i = 0; i < jobs.length; i++) {
Promise.resolve(jobs[i])
.then(res => {
resolve(res)
})
.catch(e => {
reasons[i] = e
count++
if (count === jobs.length) {
reject(reasons)
}
})
}
});
};
  1. 实现 Promise.allSettled

  2. Promise.allSettled 总会返回一个兑现的 promise

  3. 当入参都敲定(兑现或者拒绝)时,allSettled 返回的 promise 兑现

  4. 返回值是一个{ status: ‘fufilled’ | ‘rejected’, reason?, value? }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function promiseAllSettled(jobs) {
return new Promise((resolve, reject) => {
if (!Array.isArray(jobs)) {
return reject(new Error("参数不是数组"));
}

// 处理空数组
if (jobs.length === 0) {
return resolve([]);
}

const result = [];
let count = 0;

for (let i = 0; i < jobs.length; i++) {
Promise.resolve(jobs[i])
.then((res) => {
result[i] = {
status: 'fulfilled',
value: res
};
count++;
if (count === jobs.length) {
resolve(result);
}
})
.catch((e) => {
result[i] = {
status: 'rejected',
reason: e
};
count++;
if (count === jobs.length) {
resolve(result);
}
});
}
});
}
  1. 实现红绿灯机制:初始化绿灯,过4s后变成黄灯,过1s后变成红灯,过5s后变成绿灯,以此循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const states = [
{ color: 'green', duration: 4 },
{ color: 'yellow', duration: 1 },
{ color: 'red', duration: 5 },
]

// sleep 实现
const sleep = (duration) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, duration * 1000)
})
}

const trafficLight = async () => {
while(true) {
for (const state of states) {
const { color, duration } = state
console.log(color)
await sleep(duration)
}
}
}

trafficLight()

// then实现
const startLight = () => {
let chian = Promise.resolve()
const runCircle = () => {
states.forEach(state => {
chain = chain.then(() => changeTo(state))
})
chain.then(runCircle)
}
}
startLight()
// 递归实现
  1. 异步任务 compose 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const task1 = (pre) => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(pre * 3)
}, 1000)
})

const task2 = (pre) => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(pre + 4)
}, 1000)
})

const task3 = (pre) => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(pre + 6)
}, 1000)
})

const compose = (queue = [], initialValue) => {
const initial = Promise.resolve(initialValue)
return queue.reduce((prePromise, currTask) => {
return prePromise.then(currTask)
}, initial)
}

compose([task1, task2, task3], 2).then((res) => {
console.log(res)
})
  1. 不定参数柯里化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 不定参数的柯里化实现
const sum = (...args) => {
return args.reduce((total, curr) => {
return total + curr
}, 0)
}

const curry = (fn) => {
let totalArgs = []
const curried = (...args) => {
if (args.length === 0) {
const result = fn.apply(null, totalArgs)
totalArgs = []
return result
} else {
totalArgs.push(...args)
return curried
}
}
return curried
}
const curriedSum = curry(sum)

console.log(curriedSum(1)(2)(3)(4)())
  1. 防抖 / 节流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 防抖
const debounce = (fn, delay) => {
let timer = null
return function(...args) {
const context = this
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(context, args)
}, delay)
}
}

// 节流 (非立即执行/延迟响应)
const throttle = (fn, frequent) => {
let timer = null
return function(...args) {
const context = this
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, frequent)
}
}

// 节流 立即触发一次
const throttle_immediate = (fn, delay) => {
let lastTime = 0
return function(...args) {
const context = this
const currentTime = Date.now()
if (Date.now - lastTime > delay) {
fn.apply(context, args)
lastTime = currentTime
}
}
}

感谢您的支持 | Thank you for supporting

手撕代码
http://example.com/2025/10/17/8CodeByHand/
作者
Eli Bi
发布于
2025年10月17日
更新于
2025年10月20日
许可协议