笔试题
hardMan 函数
题目要求:
// 写一个 hardMan函数,满足控制台打印效果如下:
hardMan('小明')
//> Hi! I am 小明.
hardMan('小明').study('学习')
//> Hi! I am 小明.
//> I am studying 学习.
hardMan('小明').rest(3).study('学习')
//> Hi! I am 小明.
// 此时等待三秒钟
//> Wait 3 seconds.
//> I am studying 学习.
hardMan('小明').restFirst(3).study('学习')
// 此时等待三秒钟
//> Wait 3 seconds.
//> Hi! I am 小明.
//> I am studying 学习.
可以看到 hardMan 函数需要有异步等待、链式调用、以及任务调度。
分析:
- 链式调用,可以通过每次返回 this 实 例实现。
- 异步等待,可以将每次调用包装成一个 Promise task 放入数组中,最后依次执行.
- restFirst 方法,将任务放入数组的开头,可以保证先执行。
这里在 setTimeout 调用了 runTasks 方法,保证了所有方法都放入到了 tasks 数组中.
class HardMan {
constructor(name) {
this.name = name
this.tasks = []
this.tasks.push(
() =>
new Promise((resolve) => {
console.log(`Hi! I am ${this.name}`)
resolve()
})
)
setTimeout(() => this.runTasks())
}
async runTasks() {
for (const task of this.tasks) {
await task()
}
}
study(job) {
this.tasks.push(
() =>
new Promise((resolve) => {
console.log(`I am studying ${job}`)
resolve()
})
)
return this
}
rest(seconds) {
this.tasks.push(
() =>
new Promise((resolve) => {
setTimeout(() => {
console.log(`Wait ${seconds} seconds.`)
resolve()
}, seconds * 1000)
})
)
return this
}
restFirst(seconds) {
this.tasks.unshift(
() =>
new Promise((resolve) => {
setTimeout(() => {
console.log(`Wait ${seconds} seconds.`)
resolve()
}, seconds * 1000)
})
)
return this
}
}
const hardMan = (name) => new HardMan(name)
hardMan('小明').restFirst(3).study('学习')
并发请求数量控制
题目要求:
实现一个并发请求函数 concurrencyRequest(urls, maxNum),要求如下:
- 要求最大并发数 maxNum
- 每当有一个请求返回,就留下一个空位,可以增加新的请求
- 所有请求完成后,结果按照 urls 里面的顺序依次打出(发送请求的函数可以直接使用 fetch 即可)
const concurrencyRequest = (urls, maxNum) =>
new Promise((resolve) => {
const len = urls.length
let index = 0 // 请求索引
let count = 0 // 当前请求完成的个数
const res = []
async function request() {
const url = urls[index]
const i = index // 保存索引,使得请求和响应保持相同顺序
index++
try {
const resp = await fetch(url)
res[i] = resp
} catch (error) {
res[i] = error
} finally {
count++
if (count === len) {
resolve(res)
}
if (index < len) {
request()
}
}
}
for (let index = 0; index < Math.min(maxNum, urls.length); index++) {
request()
}
})
这里有两个额外的变量 index 和 count,分别用于记录当前发出请求的索引和请求完成的个数。
测试用例:
const urls = []
for (let i = 1; i <= 20; i++) {
urls.push(`https://jsonplaceholder.typicode.com/todos/${i}`)
}
concurrencyRequest(urls, 3).then((res) => {
console.log(res)
})
异步任务并发执行
题目要求如下:
实现 SuperTask 类.
const timeout = (timer) =>
new Promise((resolve) =>
setTimeout(() => {
resolve()
}, timer * 1000)
)
class SuperTask {}
const superTask = new SuperTask()
const addTask = (time, name) =>
superTask
.add(() => timeout(time))
.then(() => {
console.log(`任务${name}完成`)
})
addTask(10, '