查建筑公司资质的网站,html网站的规划与建设6,网页制作实训内容,东莞外贸网站制作微信搜索“好朋友乐平”关注公众号。 1. Promise 对象池
请你编写一个异步函数 promisePool #xff0c;它接收一个异步函数数组 functions 和 池限制 n。它应该返回一个 promise 对象#xff0c;当所有输入函数都执行完毕后#xff0c;promise 对象就执行完毕。
池限制 定…
微信搜索“好朋友乐平”关注公众号。 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。
在 t0 时执行前两个函数。池大小限制达到 2。
当 t300 时第一个函数执行完毕后执行第3个函数。池大小为 2。
在 t400 时第二个函数执行完毕后。没有什么可执行的了。池大小为 1。
在 t500 时第三个函数执行完毕后。池大小为 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]
解释
在 t0 时所有3个函数都被执行。池的限制大小 5 永远不会满足。
在 t200 时第三个函数执行完毕后。池大小为 2。
在 t300 时第一个函数执行完毕后。池大小为 1。
在 t400 时第二个函数执行完毕后。池大小为 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]
解释
在 t0 时执行第一个函数。池大小为1。
当 t300 时第一个函数执行完毕后执行第二个函数。池大小为 1。
当 t700 时第二个函数执行完毕后执行第三个函数。池大小为 1。
在 t900 时第三个函数执行完毕后。池大小为 0因此返回的 Promise 也执行完成。实现
type F () Promiseany;function promisePool(functions: F[], n: number): Promiseany[] {let fNext 0; // 下一个要执行的函数的索引// 递归调用该函数以依次执行下一个函数const evaluateNext async (): Promisevoid {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 Promisenumberasync function addTwoPromises(promise1: P, promise2: P): P {};/*** addTwoPromises(Promise.resolve(2), Promise.resolve(2))* .then(console.log); // 4*/实现
async function addTwoPromises(promise1: Promisenumber, promise2: Promisenumber): Promisenumber {return await promise1 await promise2
};async function addTwoPromises(promise1: Promisenumber, promise2: Promisenumber): Promisenumber {return await Promise.all([promise1, promise2]).then(([a, b]) a b)
};async function addTwoPromises(promise1: Promisenumber, promise2: Promisenumber): Promisenumber {const [a, b] await Promise.all([promise1, promise2])return a b
};async function addTwoPromises(promise1: Promisenumber, promise2: Promisenumber): Promisenumber {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所以在 t50ms 时拒绝因为达到了超时时间。
示例 2输入
fn async (n) {await new Promise(res setTimeout(res, 100));return n * n;
}
inputs [5]
t 150
输出{resolved:25,time:100}
解释
在 t100ms 时执行 5*525 没有达到超时时间。
示例 3输入
fn async (a, b) {await new Promise(res setTimeout(res, 120));return a b;
}
inputs [5,10]
t 150
输出{resolved:15,time:120}
解释
在 t120ms 时执行 51015没有达到超时时间。
示例 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[]) Promiseany;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 t100ms*/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 () Promiseanyfunction 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 Rejectedfn 以回调函数作为第一个参数和 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[]) Promisenumberfunction 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[]): PromiseObj[] {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 FnT () PromiseTasync function promiseAllT(functions: (() PromiseT)[]): PromiseT[] {return new PromiseT[]((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): Promisevoid {return new Promisevoid(resolve {setTimeout(resolve, millis);});
}9. 异步任务调度器
描述实现一个带并发限制的异步调度器 Scheduler保证同时运行的任务最多有 limit 个。
实现
type PromiseCreator () Promisevoid;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 Promisevoid((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 411. 设计可取消 Promise
实现
type CancellablePromiseT [PromiseT, () void];function makeCancellableT(promise: PromiseT): CancellablePromiseT {let rejectFn: (reason?: any) void;const wrappedPromise new PromiseT((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 Promisestring((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原文地址