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。
在 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原文地址
相关文章:

Promise 常见题目
微信搜索“好朋友乐平”关注公众号。 1. Promise 对象池 请你编写一个异步函数 promisePool ,它接收一个异步函数数组 functions 和 池限制 n。它应该返回一个 promise 对象,当所有输入函数都执行完毕后,promise 对象就执行完毕。 池限制 定…...
五大架构风格之五:仓库架构风格
仓库架构风格: 仓库风格架构(Repository Architecture Style)是一种软件架构模式,它主要用于处理系统中的持久化数据存储和检索。在这一风格中,仓库(Repository)作为应用程序与数据库或其他持久…...

探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密
设计模式专栏:http://t.csdnimg.cn/U54zu 目录 引言:探索简化之路 一、起源和演变 二、场景案例分析 2.1 不用模式实现:用一坨坨代码实现 2.2 问题 2.3 外观模式重构代码 定义 界面 接口 利用外观模式解决问题步骤 外观模式结构和说明 重构…...

java之Maven
1. maven Maven是管理和构建java项目的工具 项目依赖资源(jar包)的管理,避免版本冲突统一项目结构项目构建,标准跨平台(Linux,window,MacOS)的自动化项目管理 2.maven依赖仓库 2.maven安装 maven安装视频教程 3. IDEA集成Maven 4. maven的依赖范围 5. maven生命…...

Elasticsearch(四)
是这样的前面的几篇笔记,感觉对我没有形成知识体系,感觉乱糟糟的,只是大概的了解了一些基础知识,仅此而已,而且对于这技术栈的学习也是为了在后面的java开发使用,但是这里的API学的感觉有点乱!然…...

蓝桥杯-X图形
问题描述 给定一个字母矩阵。一个 X 图形由中心点和由中心点向四个 45度斜线方向引出的直线段组成,四条线段的长度相同,而且四条线段上的字母和中心点的字母相同。 一个 X 图形可以使用三个整数 r,c,L 来描述,其中 r,c 表示中心点位于第 r 行…...

2. Maven 继承与聚合
目录 2. 2.1 继承 2.2继承关系 2.2.1 思路分析 2.2.2 实现 2.1.2 版本锁定 2.1.2.1 场景 2.1.2.2 介绍 2.1.2.3 实现 2.1.2.4 属性配置 2.2 聚合 2.2.1 介绍 2.2.2 实现 2.3 继承与聚合对比 maven1:分模块设计开发 2. 在项目分模块开发之后啊&#x…...

如何把手机平板变为电脑的屏幕
文章目录 安装软件运行效果结尾 本文首发地址 https://h89.cn/archives/181.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 闲置的手机平板、触屏音箱等,均可作为电脑的扩展屏,为电脑增加一块显示屏,本文介绍如何使用免费的软件s…...

Amazon Dynamo学习总结
目录 一、Amazon Dynamo的问世 二、Amazon Dynamo主要技术概要 三、数据划分算法 四、数据复制 五、版本控制 六、故障处理 七、成员和故障检测 一、Amazon Dynamo的问世 Amazon Dynamo是由亚马逊在2007年开发的一种高度可扩展和分布式的键值存储系统,旨在解…...
appium抓包总结
appium抓包总结 背景:有些app通过抓包工具charles等抓不到接口数据,应为这一类抓包工具只能抓到应用层的数据包,而某些app的接口是走的传输层协议,所以此时只能通过AppIUM工具来进行抓包。 1、Appium 是什么? Appium…...

arcgis各种版本下载
arcgic 下载!!! ArcGIS是一款地理信息系统软件,由美国Esri公司开发。它提供了一系列完整的GIS功能,包括地图制作、空间数据管理、空间分析、空间信息整合、发布与共享等。ArcGIS是一个可扩展的GIS平台,提供…...

第五篇:MySQL常见数据类型
MySQL中的数据类型有很多,主要分为三类:数值类型、字符串类型、日期时间类型 三个表格都在此网盘中,需要者可移步自取,如果觉得有帮助希望点个赞~ MySQL常见数据类型表 数值类型 (注:decimal类型举例,如1…...
Oracle用BETWEEN AND查某年的数据可能会丢失条数
随便找一张有日期(字段类型为DATE)的表即可测试。 假设存在这样一张表HOLIDAY,里面存储的是某些国家(表字段为COUNTRY_CODE)某些年的法定假日日期(表字段为HOLIDAY_DATE)。 我想查中国在2023年和2024年的法定假日日期。 BETWEEN AND 首先想…...

Nuscenes数据集点云数据如何转换到图像上
零、概要 注意:该文章是手写ai自动驾驶,Nuscenes数据集的笔记。 首先,学习需要使用到 nuScenes 数据集。python 工具需要使用到 nuscenes-devkit、pyquaternion from nuscenes.nuscenes import NuScenes from pyquaternion import Quatern…...

【C语言期末】商品管理系统
本文资源:https://download.csdn.net/download/weixin_47040861/88820155 1.题目要求 商品管理系统 商品信息包括:包括编号、类别、名称、价格、折扣比例、生产时间 、存货数量等要求:1、信息首先保存在文件中,然后打开文件进行…...

单片机学习笔记---串口通信(2)
目录 串口内部结构 串口相关寄存器 串口控制寄存器SCON SM0和SM1 SM2 REN TB8和RB8 TI和RI 电源控制寄存器PCON SMOD 串口工作方式 方式0 方式0输出: 方式0输入 方式1 方式1输出。 方式1输入 方式2和方式3 方式2和方式3输出: 方式2和…...
【Java】乐观锁有哪些常见实现方式?
Java中的乐观锁主要有两种常见的实现方式: CAS(Compare and Swap):这是实现乐观锁的核心算法。CAS操作包含三个参数:内存地址V、旧的预期值A和要修改的新值B。执行CAS操作时,会先比较内存地址V中的值是否等…...

Javaweb之SpringBootWeb案例之登录校验功能的详细解析
2. 登录校验 2.1 问题分析 我们已经完成了基础登录功能的开发与测试,在我们登录成功后就可以进入到后台管理系统中进行数据的操作。 但是当我们在浏览器中新的页面上输入地址:http://localhost:9528/#/system/dept,发现没有登录仍然可以进…...

CSS之盒模型
盒模型概念 浏览器盒模型(Box Model)是CSS中的基本概念,它描述了元素在布局过程中如何占据空间。盒模型由内容(content)、内边距(padding)、边框(border)、和外边距&…...

博客系统-SpringBoot版本
相比于之前使用Servlet来完成的博客系统,SpringBoot版本的博客系统功能更完善,使用到的技术更接近企业级,快来看看吧~ 目录 1.项目介绍 2.数据库准备 3.实体化类 4.返回格式 5.登录和注册功能 6.登出(注销)功能…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...

数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...

PLC入门【4】基本指令2(SET RST)
04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C),从 文件 - 主画面,“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...

Axure Rp 11 安装、汉化、授权
Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接:https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...