黄岛开发区做网站的公司推广普通话的意义50字
微信搜索“好朋友乐平”关注公众号。
1. Promise 对象池
请你编写一个异步函数 promisePool
,它接收一个异步函数数组 functions
和 池限制 n
。它应该返回一个 promise
对象,当所有输入函数都执行完毕后,promise
对象就执行完毕。
池限制 定义是一次可以挂起的最多 promise
对象的数量。promisePool
应该开始执行尽可能多的函数,并在旧的 promise
执行完毕后继续执行新函数。promisePool
应该先执行 functions[i]
,再执行 functions[i + 1]
,然后执行 functions[i + 2]
,等等。当最后一个 promise
执行完毕时,promisePool
也应该执行完毕。
例如,如果 n = 1
, promisePool
在序列中每次执行一个函数。然而,如果 n = 2
,它首先执行两个函数。当两个函数中的任何一个执行完毕后,再执行第三个函数(如果它是可用的),依此类推,直到没有函数要执行为止。
你可以假设所有的 functions
都不会被拒绝。对于 promisePool
来说,返回一个可以解析任何值的 promise
都是可以接受的。
示例 1:输入:
functions = [() => new Promise(res => setTimeout(res, 300)),() => new Promise(res => setTimeout(res, 400)),() => new Promise(res => setTimeout(res, 200))
]
n = 2
输出:[[300,400,500],500]
解释
传递了三个函数。它们的睡眠时间分别为 300ms、 400ms 和 200ms。
在 t=0 时,执行前两个函数。池大小限制达到 2。
当 t=300 时,第一个函数执行完毕后,执行第3个函数。池大小为 2。
在 t=400 时,第二个函数执行完毕后。没有什么可执行的了。池大小为 1。
在 t=500 时,第三个函数执行完毕后。池大小为 0,因此返回的 promise 也执行完成。
示例 2:输入:
functions = [() => new Promise(res => setTimeout(res, 300)),() => new Promise(res => setTimeout(res, 400)),() => new Promise(res => setTimeout(res, 200))
]
n = 5
输出:[[300,400,200],400]
解释:
在 t=0 时,所有3个函数都被执行。池的限制大小 5 永远不会满足。
在 t=200 时,第三个函数执行完毕后。池大小为 2。
在 t=300 时,第一个函数执行完毕后。池大小为 1。
在 t=400 时,第二个函数执行完毕后。池大小为 0,因此返回的 promise 也执行完成。
示例 3:输入:
functions = [() => new Promise(res => setTimeout(res, 300)),() => new Promise(res => setTimeout(res, 400)),() => new Promise(res => setTimeout(res, 200))
]
n = 1
输出:[[300,700,900],900]
解释:
在 t=0 时,执行第一个函数。池大小为1。
当 t=300 时,第一个函数执行完毕后,执行第二个函数。池大小为 1。
当 t=700 时,第二个函数执行完毕后,执行第三个函数。池大小为 1。
在 t=900 时,第三个函数执行完毕后。池大小为 0,因此返回的 Promise 也执行完成。
实现
type F = () => Promise<any>;function promisePool(functions: F[], n: number): Promise<any[]> {let fNext = 0; // 下一个要执行的函数的索引// 递归调用该函数以依次执行下一个函数const evaluateNext = async (): Promise<void> => {if (fNext >= functions.length) {// 如果所有函数都已执行,则退出return;}const fn = functions[fNext++]; // 获取下一个要执行的函数await fn(); // 执行函数并等待其完成await evaluateNext(); // 递归调用 evaluateNext,继续执行下一个函数};// 同时启动 n 个 evaluateNext()调用来保持 n 个异步任务并发const runners = new Array(n).fill(null).map(() => evaluateNext());// 等待所有启动的任务完成return Promise.all(runners)
}
2. 两个 Promise 对象相加
给定两个 promise 对象 promise1 和 promise2,返回一个新的 promise。promise1 和 promise2 都会被解析为一个数字。返回的 Promise 应该解析为这两个数字的和。
示例 1:输入:
promise1 = new Promise(resolve => setTimeout(() => resolve(2), 20)),
promise2 = new Promise(resolve => setTimeout(() => resolve(5), 60))
输出:7
解释:两个输入的 Promise 分别解析为值 2 和 5。返回的 Promise 应该解析为 2 + 5 = 7。返回的 Promise 解析的时间不作为判断条件。
示例 2:输入:
promise1 = new Promise(resolve => setTimeout(() => resolve(10), 50)),
promise2 = new Promise(resolve => setTimeout(() => resolve(-12), 30))
输出:-2
解释:两个输入的 Promise 分别解析为值 10 和 -12。返回的 Promise 应该解析为 10 + -12 = -2。
type P = Promise<number>async function addTwoPromises(promise1: P, promise2: P): P {};/*** addTwoPromises(Promise.resolve(2), Promise.resolve(2))* .then(console.log); // 4*/
实现
async function addTwoPromises(promise1: Promise<number>, promise2: Promise<number>): Promise<number> {return await promise1 + await promise2
};async function addTwoPromises(promise1: Promise<number>, promise2: Promise<number>): Promise<number> {return await Promise.all([promise1, promise2]).then(([a, b]) => a + b)
};async function addTwoPromises(promise1: Promise<number>, promise2: Promise<number>): Promise<number> {const [a, b] = await Promise.all([promise1, promise2])return a + b
};async function addTwoPromises(promise1: Promise<number>, promise2: Promise<number>): Promise<number> {return new Promise((resolve, reject) => {Promise.all([promise1, promise2]).then(([a, b]) => {resolve(a + b)}).catch(reject)})
};
3. 有时间限制的 Promise 对象
请你编写一个函数,它接受一个异步函数 fn 和一个以毫秒为单位的时间 t。它应根据限时函数返回一个有 限时 效果的函数。函数 fn 接受提供给 限时 函数的参数。
限时 函数应遵循以下规则:
如果 fn 在 t 毫秒的时间限制内完成,限时 函数应返回结果。
如果 fn 的执行超过时间限制,限时 函数应拒绝并返回字符串 “Time Limit Exceeded” 。
示例 1:输入:
fn = async (n) => {await new Promise(res => setTimeout(res, 100));return n * n;
}
inputs = [5]
t = 50
输出:{"rejected":"Time Limit Exceeded","time":50}
解释:
const limited = timeLimit(fn, t)
const start = performance.now()
let result;
try {const res = await limited(...inputs)result = {"resolved": res, "time": Math.floor(performance.now() - start)};
} catch (err) {result = {"rejected": err, "time": Math.floor(performance.now() - start)};
}
console.log(result) // 输出结果提供的函数设置在 100ms 后执行完成,但是设置的超时时间为 50ms,所以在 t=50ms 时拒绝因为达到了超时时间。
示例 2:输入:
fn = async (n) => {await new Promise(res => setTimeout(res, 100));return n * n;
}
inputs = [5]
t = 150
输出:{"resolved":25,"time":100}
解释:
在 t=100ms 时执行 5*5=25 ,没有达到超时时间。
示例 3:输入:
fn = async (a, b) => {await new Promise(res => setTimeout(res, 120));return a + b;
}
inputs = [5,10]
t = 150
输出:{"resolved":15,"time":120}
解释:
在 t=120ms 时执行 5+10=15,没有达到超时时间。
示例 4:输入:
fn = async () => {throw "Error";
}
inputs = []
t = 1000
输出:{"rejected":"Error","time":0}
解释:
此函数始终丢出 Error提示:0 <= inputs.length <= 10
0 <= t <= 1000
fn 返回一个 Promise 对象
实现
type Fn = (...params: any[]) => Promise<any>;function timeLimit(fn: Fn, t: number): Fn {return async function(...args) {return new Promise(async (resolve, reject) => {const timeout = setTimeout(() => {reject("Time Limit Exceeded");}, t);try {const result = await fn(...args);resolve(result);} catch(err) {reject(err);}clearTimeout(timeout);});};
};/*** const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 100);* limited(150).catch(console.log) // "Time Limit Exceeded" at t=100ms*/
4. 延迟每个 Promise 对象的解析
给定一个函数数组 functions 和一个数字 ms,返回一个新的函数数组。
functions 是一个返回 Promise 对象的函数数组。
ms 表示延迟的时间,以毫秒为单位。它决定了在新数组中的每个函数返回的 Promise 在解析之前等待的时间。
新数组中的每个函数应该返回一个 Promise 对象,在延迟了 ms 毫秒后解析,保持原始 functions 数组中的顺序。delayAll 函数应确保从 functions 中的每个 Promise 都被延迟执行,形成返回延迟的 Promise 的函数的新数组。
示例 1:输入:
functions = [() => new Promise((resolve) => setTimeout(resolve, 30))
],
ms = 50
输出:[80]
解释:数组中的 Promise 在 30 毫秒后解析,但被延迟了 50 毫秒,所以总共延迟了 30 毫秒 + 50 毫秒 = 80 毫秒。
示例 2:输入:
functions = [() => new Promise((resolve) => setTimeout(resolve, 50)),() => new Promise((resolve) => setTimeout(resolve, 80))
],
ms = 70
输出:[120,150]
解释:数组中的 Promise 在 50 毫秒和 80 毫秒后解析,但它们被延迟了 70 毫秒,所以总共延迟了 50 毫秒 + 70 毫秒 = 120 毫秒 和 80 毫秒 + 70 毫秒 = 150 毫秒。提示:functions 是一个返回 Promise 对象的函数数组
10 <= ms <= 500
1 <= functions.length <= 10
实现
type Fn = () => Promise<any>function delayAll(functions: Fn[], ms: number): Fn[] {return functions.map(fn => () => new Promise(res => {setTimeout(() => {res(fn())}, ms)}))
};
5. 转换回调函数为 Promise 函数
编写一个函数,接受另一个函数 fn ,并将基于回调函数的函数转换为基于 Promise 的函数。
promisify 函数接受一个函数 fn ,fn 将回调函数作为其第一个参数,并且还可以接受其他额外的参数。
promisfy 返回一个新函数,新函数会返回一个 Promise 对象。当回调函数被成功调用时,新函数返回的 Promise 对象应该使用原始函数的结果进行解析;当回调函数被调用出现错误时,返回的 Promise 对象应该被拒绝并携带错误信息。最终返回的基于 Promise 的函数应该接受额外的参数作为输入。
以下是一个可以传递给 promisify 的函数示例:function sum(callback, a, b) {if (a < 0 || b < 0) {const err = Error('a and b must be positive');callback(undefined, err);} else {callback(a + b);}
}
这是基于 Promise 的等效代码:async function sum(a, b) {if (a < 0 || b < 0) {throw Error('a and b must be positive');} else {return a + b;}
}示例 1:输入:
fn = (callback, a, b, c) => {return callback(a * b * c);
}
args = [1, 2, 3]
输出:{"resolved": 6}
解释:
const asyncFunc = promisify(fn);
asyncFunc(1, 2, 3).then(console.log); // 6fn 以回调函数作为第一个参数和 args 作为其余参数进行调用。当使用 (1, 2, 3) 调用时,基于 Promise 的 fn 将解析为值 6。
示例 2:输入:
fn = (callback, a, b, c) => {callback(a * b * c, "Promise Rejected");
}
args = [4, 5, 6]
输出:{"rejected": "Promise Rejected"}
解释:
const asyncFunc = promisify(fn);
asyncFunc(4, 5, 6).catch(console.log); // "Promise Rejected"fn 以回调函数作为第一个参数和 args 作为其余参数进行调用。在回调函数的第二个参数中,接受一个错误消息,因此当调用 fn 时,Promise 被拒绝并携带回调函数中提供的错误消息。请注意,不管将什么作为回调函数的第一个参数传递都无关紧要。提示:1 <= args.length <= 100
0 <= args[i] <= 104
实现
type CallbackFn = (next: (data: number, error: string) => void,...args: number[]
) => void
type Promisified = (...args: number[]) => Promise<number>function promisify(fn: CallbackFn): Promisified {return async function(...args) {return new Promise((resolve, reject) => {fn((data: number, error: string) => {if (error) reject(error);resolve(data);}, ...args);});};
};
6. 并行执行 Promise 以获取独有的结果
给定一个数组 functions,返回一个 promise 对象 promise。functions 是一个返回多个 promise 对象 fnPromise 的函数数组。每个 fnPromise 可以被解析(resolved)或拒绝(rejected)。
如果 fnPromise 被解析:obj = { status: "fulfilled", value: resolved value}如果 fnPromise 被拒绝:obj = { status: "rejected", reason: 拒绝的原因(捕获的错误消息)}该 promise 应该返回一个包含这些对象 obj 的数组。数组中的每个 obj 应该对应原始函数数组中的多个 promise 对象,并保持相同的顺序。请在不使用内置方法 Promise.allSettled() 的情况下实现它。示例 1:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(15), 100))
]
输出:{"t":100,"values":[{"status":"fulfilled","value":15}]}
解释:
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}]}
})返回的 promise 在 100 毫秒内解析。由于函数数组中的 promise 被解析,返回的 promise 的解析值设置为[{"status":"fulfilled","value":15}]。
示例 2:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(20), 100)),() => new Promise(resolve => setTimeout(() => resolve(15), 100))
]
输出:
{"t":100,"values": [{"status":"fulfilled","value":20},{"status":"fulfilled","value":15}]
}
解释:返回的 promise 在 100 毫秒内解析,因为解析时间取决于需要最长时间来解析的 promise。由于函数数组中的 promises 被解析,返回的 promise 的解析值设置为[{"status":"fulfilled","value":20},{"status":"fulfilled","value":15}]。
示例 3:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(30), 200)),() => new Promise((resolve, reject) => setTimeout(() => reject("Error"), 100))
]
输出:
{"t":200,"values": [{"status":"fulfilled","value":30},{"status":"rejected","reason":"Error"}]
}
解释:返回的 promise 在 200 毫秒内解析,因为解析时间取决于需要最长时间来解析的 promise。由于函数数组中的一个 promise 被解析,另一个被拒绝,返回的 promise 的解析值设置为[{"status":"fulfilled","value":30},{"status":"rejected","reason":"Error"}]。数组中的每个对象对应原始函数数组中的 promise,并保持相同的顺序。提示:1 <= functions.length <= 10
实现
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((resolve) => {const resultArray = [];let completedCount = 0;for (let i = 0; i < functions.length; i++) {const fnPromise = functions[i]();fnPromise.then((value) => {resultArray[i] = { status: "fulfilled", value };}).catch((reason) => {resultArray[i] = { status: "rejected", reason };}).finally(() => {completedCount++;if (completedCount === functions.length) {resolve(resultArray);}});}});
};/*** 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}]}* })*/
7. 并行执行异步函数
给定一个异步函数数组 functions,返回一个新的 promise 对象 promise。数组中的每个函数都不接受参数并返回一个 promise。所有的 promise 都应该并行执行。
promise resolve 条件:
当所有从 functions 返回的 promise 都成功的并行解析时。promise 的解析值应该是一个按照它们在 functions 中的顺序排列的 promise 的解析值数组。promise 应该在数组中的所有异步函数并行执行完成时解析。
promise reject 条件:
当任何从 functions 返回的 promise 被拒绝时。promise 也会被拒绝,并返回第一个拒绝的原因。
请在不使用内置的 Promise.all 函数的情况下解决。
示例 1:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(5), 200))
]
输出:{"t": 200, "resolved": [5]}
解释:
promiseAll(functions).then(console.log); // [5]单个函数在 200 毫秒后以值 5 成功解析。
示例 2:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(1), 200)),() => new Promise((resolve, reject) => setTimeout(() => reject("Error"), 100))
]
输出:{"t": 100, "rejected": "Error"}
解释:由于其中一个 promise 被拒绝,返回的 promise 也在同一时间被拒绝并返回相同的错误。
示例 3:输入:functions = [() => new Promise(resolve => setTimeout(() => resolve(4), 50)),() => new Promise(resolve => setTimeout(() => resolve(10), 150)),() => new Promise(resolve => setTimeout(() => resolve(16), 100))
]
输出:{"t": 150, "resolved": [4, 10, 16]}
解释:所有的 promise 都成功执行。当最后一个 promise 被解析时,返回的 promise 也被解析了。提示:函数 functions 是一个返回 promise 的函数数组
1 <= functions.length <= 10
实现
type Fn<T> = () => Promise<T>async function promiseAll<T>(functions: (() => Promise<T>)[]): Promise<T[]> {return new Promise<T[]>((resolve, reject) => {if(functions.length === 0) {resolve([]);return;}const res: T[] = new Array(functions.length).fill(null);let resolvedCount = 0;functions.forEach(async (el, idx) => {try {const subResult = await el();res[idx] = subResult;resolvedCount++;if(resolvedCount === functions.length) {resolve(res);}} catch(err) {reject(err);}});});
};/*** const promise = promiseAll([() => new Promise(res => res(42))])* promise.then(console.log); // [42]*/
8. 睡眠函数
请你编写一个异步函数,它接收一个正整数参数 millis ,并休眠 millis 毫秒。要求此函数可以解析任何值。示例 1:输入:millis = 100
输出:100
解释:
在 100ms 后此异步函数执行完时返回一个 Promise 对象
let t = Date.now();
sleep(100).then(() => {console.log(Date.now() - t); // 100
});
示例 2:输入:millis = 200
输出:200
解释:在 200ms 后函数执行完时返回一个 Promise 对象提示:1 <= millis <= 1000
实现
async function sleep(millis: number): Promise<void> {return new Promise<void>(resolve => {setTimeout(resolve, millis);});
}
9. 异步任务调度器
描述:实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有 limit 个。
实现
type PromiseCreator = () => Promise<void>;class Scheduler {private queue: PromiseCreator[]; // 用队列保存正在执行的任务private runCount: number; // 计数正在执行的任务个数private maxCount: number; // 允许并发的最大个数constructor(limit: number) {this.queue = [];this.runCount = 0;this.maxCount = limit;}add(time: number, data: string) {const promiseCreator: PromiseCreator = () => {return new Promise<void>((resolve) => {setTimeout(() => {console.log(data);resolve();}, time);});}this.queue.push(promiseCreator);// 每次添加的时候都会尝试去执行任务this.request();}private request() {// 队列中还有任务才会被执行if (this.queue.length && this.runCount < this.maxCount) {this.runCount++;// 执行先加入队列的函数this.queue.shift()!().then(() => {this.runCount--;// 尝试进行下一次任务this.request();});}}
}// 测试
const scheduler = new Scheduler(2);const addTask = (time: number, data: string) => {scheduler.add(time, data);
}addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 输出结果 2 3 1 4
11. 设计可取消 Promise
实现
type CancellablePromise<T> = [Promise<T>, () => void];function makeCancellable<T>(promise: Promise<T>): CancellablePromise<T> {let rejectFn: (reason?: any) => void;const wrappedPromise = new Promise<T>((resolve, reject) => {rejectFn = reject; // 保存 reject 函数引用以便后续调用promise.then((value) => {if (rejectFn !== null) { // 如果没有被取消,那么解决 wrappedPromiseresolve(value);rejectFn = null; // 清除 rejectFn 引用,避免内存泄漏}},(error) => {if (rejectFn !== null) { // 如果没有被取消,那么拒绝 wrappedPromisereject(error);rejectFn = null; // 清除 rejectFn 引用,避免内存泄漏}});});const cancel = () => {if (rejectFn !== null) {rejectFn({ cancelled: true }); // 立即拒绝 wrappedPromiserejectFn = null; // 防止内存泄漏,清除 rejectFn 引用}};return [wrappedPromise, cancel];
}// 使用示例
const [cancellablePromise, cancel] = makeCancellable(new Promise<string>((resolve) => {setTimeout(() => {resolve("Resolved after 2 seconds");}, 2000);
}));cancellablePromise.then((result) => {console.log(result);}).catch((error) => {if (error && error.cancelled) {console.log("Promise was cancelled");} else {console.log("Promise was rejected with error:", error);}});// 立即取消 Promise
cancel();
10. 多个 Callback 函数 Promise 化的测试用例
// Node.js 风格的 myFunction
function myFunction(cb1, cb2, cb3) {// 模拟异步操作,例如 I/OsetTimeout(() => cb1(null, "result1"), Math.floor(Math.random() * 1000));setTimeout(() => cb2(null, "result2"), Math.floor(Math.random() * 1000));setTimeout(() => cb3(null, "result3"), Math.floor(Math.random() * 1000));
}// 实现 myFunctionPromise,将 myFunction Promise 化。
// cb callback 无 error 时,则为 resolve
// 测试用例
test("a", async () => {try {const results = await myFunctionPromise();console.log(results); // 输出: ['result1', 'result2', 'result3']// 这里我们期望返回的 Promise 被成功地 resolve,并且结果按次序排列expect(results).toEqual(["result1", "result2", "result3"]);} catch (err) {// 这里处理可能出现的错误console.error(err);}
});
实现
// Promise 包装器,保证次序
function myFunctionPromise() {return new Promise((resolve, reject) => {let results = new Array(3); // 创建一个长度为 3 的数组来存储结果let count = 0;let hasErrorOccurred = false;function createFinalCallback(index) {return function (err, result) {if (hasErrorOccurred) return;if (err) {hasErrorOccurred = true;return reject(err);}results[index] = result; // 根据回调的标识符存储结果count++;if (count === 3) {resolve(results); // 当所有回调都执行完毕时,按顺序解决 Promise}};}myFunction(createFinalCallback(0),createFinalCallback(1),createFinalCallback(2));});
}
微信搜索“好朋友乐平”关注公众号。
github原文地址