【前端基础】Promise 详解
文章目录
- 什么是 Promise?
- 为什么要使用 Promise?
- 创建 Promise
- 消费 Promise (使用 Promise)
- 1. `.then(onFulfilled, onRejected)`
- 2. `.catch(onRejected)`
- 3. `.finally(onFinally)`
- Promise 链 (Promise Chaining)
- Promise 的静态方法
- 1. `Promise.resolve(value)`
- 2. `Promise.reject(reason)`
- 3. `Promise.all(iterable)`
- 4. `Promise.allSettled(iterable)` (ES2020)
- 5. `Promise.race(iterable)`
- 6. `Promise.any(iterable)` (ES2021)
- Promise 中的错误处理
- Async/Await (基于 Promise 的语法糖)
- 常见陷阱和最佳实践
Promise 是现代 JavaScript 中处理异步操作的核心机制,它极大地改善了回调函数(callback)带来的“回调地狱”问题,使异步代码更加清晰、易于管理和维护。
什么是 Promise?
Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。简单来说,Promise 是一个承诺:它承诺在未来的某个时刻会给你一个结果,这个结果要么是成功的(fulfilled/resolved),要么是失败的(rejected)。
一个 Promise 对象必然处于以下三种状态之一:
- Pending (进行中):初始状态,既没有被兑现,也没有被拒绝。异步操作正在进行中。
- Fulfilled (已兑现/已成功):意味着异步操作成功完成。Promise 有一个与之关联的值(称为 resolved value)。
- Rejected (已拒绝/已失败):意味着异步操作失败。Promise 有一个与之关联的原因(通常是一个 Error 对象,称为 rejection reason)。
一旦 Promise 的状态从 pending 变为 fulfilled 或 rejected,它的状态和结果就固定不变了,不能再次改变。这种状态转变是单向的。我们称一个 Promise 为 settled (已敲定),如果它不是 pending 状态(即已兑现或已拒绝)。
为什么要使用 Promise?
-
告别回调地狱 (Callback Hell):
当多个异步操作相互依赖时,使用传统回调函数很容易形成层层嵌套的结构,代码难以阅读和维护。Promise 通过链式调用.then()
来扁平化这种结构。// 回调地狱示例 asyncOperation1(data1, (err1, result1) => {if (err1) { /* ... */ }asyncOperation2(result1, (err2, result2) => {if (err2) { /* ... */ }asyncOperation3(result2, (err3, result3) => {// ...});}); });// 使用 Promise asyncOperation1(data1).then(result1 => asyncOperation2(result1)).then(result2 => asyncOperation3(result2)).then(result3 => { /* ... */ }).catch(error => { /* 处理任何步骤中的错误 */ });
-
更优雅的错误处理:
Promise 提供了.catch()
方法,可以集中处理链中任何一个环节发生的错误,而不需要在每个回调中单独处理。 -
更好的代码可读性和可维护性:
链式调用使得异步操作的流程更加清晰,代码结构更接近同步代码的思维方式。 -
组合异步操作:
Promise 提供了一些静态方法(如Promise.all()
,Promise.race()
)来组合多个 Promise,实现更复杂的异步逻辑。
创建 Promise
可以通过 new Promise(executor)
构造函数来创建一个 Promise 对象。executor
是一个函数,它接收两个参数:resolve
和 reject
。这两个参数本身也是函数。
executor
函数会立即同步执行。- 在
executor
函数内部,通常会执行一些异步操作。 - 当异步操作成功时,调用
resolve(value)
,将 Promise 的状态变为fulfilled
,并将value
作为其结果。 - 当异步操作失败时,调用
reject(reason)
,将 Promise 的状态变为rejected
,并将reason
(通常是一个 Error 对象) 作为其原因。
const myPromise = new Promise((resolve, reject) => {// 模拟一个异步操作console.log("Promise executor 开始执行"); // 这行会立即打印setTimeout(() => {const success = Math.random() > 0.5; // 随机成功或失败if (success) {resolve("操作成功!数据来了!"); // 成功时调用 resolve} else {reject(new Error("操作失败了,呜呜呜...")); // 失败时调用 reject}}, 1000);
});console.log("Promise 已创建"); // 这行也会在 executor 内的 setTimeout 之前打印
消费 Promise (使用 Promise)
创建了 Promise之后,我们需要使用它的结果。这主要通过以下几个方法:
1. .then(onFulfilled, onRejected)
.then()
方法接收两个可选的函数作为参数:
onFulfilled
:当 Promise 状态变为fulfilled
(成功) 时被调用,接收 Promise 的解决值作为参数。onRejected
:当 Promise 状态变为rejected
(失败) 时被调用,接收 Promise 的拒绝原因作为参数。
关键点:.then()
方法返回一个新的 Promise。这使得链式调用成为可能。
myPromise.then((value) => { // onFulfilledconsole.log("成功回调:", value);return "处理成功后的新值"; // 这个返回值会成为下一个 .then 的 onFulfilled 的参数},(error) => { // onRejectedconsole.error("失败回调 (在 then 的第二个参数中):", error.message);// 如果在这里处理了错误,并且没有重新抛出或返回一个 rejected Promise,// 那么链条会继续走向 fulfilled 状态// throw error; // 如果想让链条继续保持 rejected 状态return "从错误中恢复的值";}).then((nextValue) => {console.log("下一个成功回调:", nextValue);},(nextError) => {console.error("下一个失败回调:", nextError.message);});
2. .catch(onRejected)
.catch(onRejected)
方法仅仅是 .then(null, onRejected)
的语法糖。它用于捕获 Promise 链中任何未被处理的拒绝 (rejection)。通常放在 Promise 链的末尾,用于统一处理错误。
myPromise.then(value => {console.log("成功:", value);if (value.includes("数据")) {throw new Error("成功了,但我想抛个错试试!"); // 模拟在 then 中抛错}return value;}).catch(error => { // onRejectedconsole.error("Catch 捕获到错误:", error.message);// 错误在这里被捕获和处理// 如果不重新 throw,链条会认为错误已处理,后续的 .then (如果有 onFulfilled) 可能会执行});
3. .finally(onFinally)
.finally(onFinally)
方法接收一个回调函数 onFinally
,无论 Promise 是 fulfilled
还是 rejected
,这个回调都会被执行。
onFinally
回调不接收任何参数。- 它通常用于执行一些清理工作,比如隐藏加载指示器、关闭数据库连接等。
.finally()
也会返回一个新的 Promise,它会采用原始 Promise 的状态和值/原因 (除非onFinally
抛出错误或返回一个被拒绝的 Promise)。
myPromise.then(value => console.log("Finally 示例 - 成功:", value)).catch(error => console.error("Finally 示例 - 失败:", error.message)).finally(() => {console.log("Finally: 操作已完成,无论成功或失败都会执行我!");// 通常不在这里改变 Promise 的最终结果});
Promise 链 (Promise Chaining)
由于 .then()
, .catch()
, 和 .finally()
都返回新的 Promise 对象,我们可以将它们串联起来,形成一个 Promise 链。
- 传递值:前一个
.then
的onFulfilled
回调的返回值会作为下一个.then
的onFulfilled
回调的参数。 - 异步操作的串行化:如果
.then
的回调函数返回一个新的 Promise,那么链条会等待这个新的 Promise 完成后,才会继续执行后续的.then
。
function step1() {return new Promise(resolve => {setTimeout(() => {console.log("步骤1完成");resolve("来自步骤1的结果");}, 500);});
}function step2(dataFromStep1) {return new Promise(resolve => {setTimeout(() => {console.log("步骤2完成,接收到:", dataFromStep1);resolve("来自步骤2的结果");}, 500);});
}function step3(dataFromStep2) {return new Promise(resolve => {setTimeout(() => {console.log("步骤3完成,接收到:", dataFromStep2);resolve("最终结果");}, 500);});
}step1().then(result1 => step2(result1)) // step2 返回一个 Promise.then(result2 => step3(result2)) // step3 返回一个 Promise.then(finalResult => {console.log("所有步骤完成:", finalResult);}).catch(error => {console.error("链条中发生错误:", error);});
Promise 的静态方法
Promise
对象本身也提供了一些有用的静态方法:
1. Promise.resolve(value)
返回一个使用给定值解决的 Promise 对象。
- 如果
value
本身是一个 Promise,则返回这个 Promise。 - 如果
value
是一个 thenable 对象(即拥有.then
方法的对象),Promise.resolve
会尝试展开这个 thenable 对象,并采用其最终状态。 - 否则,返回的 Promise 将会以
value
值完成。
Promise.resolve("立即成功").then(v => console.log(v)); // 输出: 立即成功const p = new Promise(r => setTimeout(() => r("延迟成功"), 100));
Promise.resolve(p).then(v => console.log(v)); // 等待 p 完成后输出: 延迟成功
2. Promise.reject(reason)
返回一个以给定原因拒绝的 Promise 对象。
Promise.reject(new Error("立即失败")).catch(e => console.error(e.message)); // 输出: 立即失败
3. Promise.all(iterable)
接收一个 Promise 对象的可迭代对象 (例如数组) 作为参数。
- 返回一个新的 Promise。
- 这个新的 Promise 只有在可迭代对象中所有的 Promise 都成功 (fulfilled) 时才会成功。其成功的值是一个数组,包含了所有输入 Promise 的成功值,顺序与输入 Promise 在可迭代对象中的顺序一致。
- 如果可迭代对象中的任何一个 Promise 失败 (rejected),那么
Promise.all()
返回的 Promise 会立即失败,并以第一个失败的 Promise 的原因为准。
const promise1 = Promise.resolve(3);
const promise2 = 42; // 会被 Promise.resolve(42) 包装
const promise3 = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'foo');
});Promise.all([promise1, promise2, promise3]).then((values) => {console.log("Promise.all 成功:", values); // 输出: [3, 42, "foo"]
}).catch(error => {console.error("Promise.all 失败:", error);
});const promiseWithError = Promise.reject('错误了');
Promise.all([promise1, promiseWithError, promise3]).then((values) => {// 这段不会执行
}).catch(error => {console.error("Promise.all 因为一个错误而失败:", error); // 输出: 错误了
});
4. Promise.allSettled(iterable)
(ES2020)
接收一个 Promise 对象的可迭代对象作为参数。
- 返回一个新的 Promise。
- 这个新的 Promise 会在可迭代对象中所有的 Promise 都已敲定 (settled) 后(无论是 fulfilled 还是 rejected)才会完成。
- 其成功的值是一个对象数组,每个对象描述了对应 Promise 的结果,格式为:
- 成功:
{ status: 'fulfilled', value: resolvedValue }
- 失败:
{ status: 'rejected', reason: rejectionReason }
- 成功:
这对于你希望等待多个异步操作完成,但不在乎它们是否都成功的情况非常有用。
const pSuccess = Promise.resolve("成功的值");
const pFailure = Promise.reject("失败的原因");
const pPending = new Promise(r => setTimeout(() => r("稍后成功"), 200));Promise.allSettled([pSuccess, pFailure, pPending]).then(results => {results.forEach(result => {if (result.status === 'fulfilled') {console.log(`AllSettled - Fulfilled: ${result.value}`);} else {console.error(`AllSettled - Rejected: ${result.reason}`);}});// 输出:// AllSettled - Fulfilled: 成功的值// AllSettled - Rejected: 失败的原因// (等待200ms后) AllSettled - Fulfilled: 稍后成功
});
5. Promise.race(iterable)
接收一个 Promise 对象的可迭代对象作为参数。
- 返回一个新的 Promise。
- 这个新的 Promise 会在可迭代对象中的任何一个 Promise 最先敲定 (settled) 时立即敲定,并采用第一个敲定的 Promise 的状态和结果(无论是 fulfilled 还是 rejected)。
const pFast = new Promise((resolve) => setTimeout(() => resolve('快速'), 50));
const pSlow = new Promise((resolve) => setTimeout(() => resolve('慢速'), 200));
const pReject = new Promise((resolve, reject) => setTimeout(() => reject('立即拒绝'), 10));Promise.race([pFast, pSlow]).then(value => console.log("Race 胜出 (fast/slow):", value)) // 输出: 快速.catch(error => console.error("Race 失败 (fast/slow):", error));Promise.race([pFast, pReject]).then(value => console.log("Race 胜出 (fast/reject):", value)).catch(error => console.error("Race 失败 (fast/reject):", error)); // 输出: 立即拒绝
6. Promise.any(iterable)
(ES2021)
接收一个 Promise 对象的可迭代对象作为参数。
- 返回一个新的 Promise。
- 这个新的 Promise 会在可迭代对象中的任何一个 Promise 最先成功 (fulfilled) 时立即成功,并以第一个成功的 Promise 的值为准。
- 如果可迭代对象中的所有 Promise 都失败 (rejected),那么
Promise.any()
返回的 Promise 会失败,并以一个AggregateError
对象为原因。AggregateError
对象有一个errors
属性,它是一个包含了所有拒绝原因的数组。
const pErr1 = Promise.reject('第一个错误');
const pErr2 = Promise.reject('第二个错误');
const pSucc1 = new Promise(r => setTimeout(() => r('第一个成功'), 50));
const pSucc2 = new Promise(r => setTimeout(() => r('第二个成功'), 10));Promise.any([pErr1, pSucc1, pSucc2]).then(value => console.log("Any 成功:", value)) // 输出: 第二个成功 (因为它最先 fulfilled).catch(error => console.error("Any 失败:", error));Promise.any([pErr1, pErr2]).then(value => console.log("Any 成功 (全失败场景):", value)) // 不会执行.catch(error => {console.error("Any 失败 (全失败场景):", error.name); // AggregateErrorconsole.error(error.errors); // ['第一个错误', '第二个错误']});
Promise 中的错误处理
正确处理 Promise 中的错误至关重要。
-
使用
.catch()
:
最佳实践是在 Promise 链的末尾添加一个.catch()
来捕获所有未处理的拒绝。 -
.then()
的第二个参数:
虽然.then(onFulfilled, onRejected)
可以处理错误,但它不如.catch()
清晰,且如果onFulfilled
抛出错误,该错误不会被同一个.then
的onRejected
捕获,而是会传递给链中的下一个.catch()
或onRejected
。 -
Executor 中的同步错误:
如果在new Promise(executor)
的executor
函数中抛出同步错误,这个错误会被隐式捕获,并导致 Promise 立即变为 rejected 状态。new Promise((resolve, reject) => {throw new Error("Executor 中的同步错误"); }).catch(err => console.error(err.message)); // 输出: Executor 中的同步错误
-
未捕获的 Promise 拒绝 (Unhandled Rejection):
如果一个 Promise 被拒绝,并且链上没有任何.catch()
或onRejected
处理它,浏览器通常会在控制台报告一个 “Uncaught (in promise)” 错误。Node.js 环境中,这可能会导致应用进程终止(取决于版本和配置)。所以,务必处理所有可能的拒绝。
Async/Await (基于 Promise 的语法糖)
ES2017 引入了 async
和 await
关键字,它们是构建在 Promise 之上的语法糖,使得异步代码的写法更像同步代码,从而更加直观。
async function
:声明一个异步函数。异步函数会自动返回一个 Promise。如果函数内部返回一个非 Promise 值,这个值会被Promise.resolve()
包装。如果函数内部抛出错误,返回的 Promise 会被 reject。await
:只能在async function
内部使用。它会暂停异步函数的执行,等待await
后面的 Promise 完成(resolved 或 rejected)。- 如果 Promise resolved,
await
表达式的值就是 Promise 的解决值。 - 如果 Promise rejected,
await
会抛出这个拒绝的原因(通常是一个 Error 对象),这可以被async function
内部的try...catch
语句捕获。
- 如果 Promise resolved,
function fetchData(shouldFail = false) {return new Promise((resolve, reject) => {setTimeout(() => {if (shouldFail) {reject(new Error("数据获取失败 (async/await)"));} else {resolve("数据已获取 (async/await)");}}, 1000);});
}async function processData() {console.log("开始处理数据...");try {const data1 = await fetchData(); // 等待 fetchData() 完成console.log("第一份数据:", data1);const data2 = await fetchData(true); // 尝试获取会失败的数据console.log("第二份数据:", data2); // 这行不会执行} catch (error) {console.error("Async/await 捕获到错误:", error.message);} finally {console.log("数据处理流程结束 (async/await)");}
}processData();
// 输出顺序:
// 开始处理数据...
// (等待1秒)
// 第一份数据: 数据已获取 (async/await)
// (等待1秒)
// Async/await 捕获到错误: 数据获取失败 (async/await)
// 数据处理流程结束 (async/await)
async/await
极大地简化了异步流程控制,尤其是当涉及到多个 последовательных (sequential) 异步操作时。
常见陷阱和最佳实践
-
忘记
return
:在.then()
回调中,如果进行了异步操作并创建了新的 Promise,或者想将值传递给下一个.then()
,确保return
这个 Promise 或值。否则,链条可能会意外地提前继续,或者下一个.then()
接收到undefined
。 -
“吞没”错误:在
.catch()
或onRejected
中,如果没有显式地重新抛出错误 (throw error;
) 或返回一个被拒绝的 Promise,那么 Promise 链会认为错误已经被处理,并可能转为fulfilled
状态。 -
不必要的 Promise 包装:避免所谓的 “Promise constructor anti-pattern”,即在
new Promise
的 executor 中包装已经返回 Promise 的函数。// 反模式 function getUserDataWrapper(userId) {return new Promise((resolve, reject) => { // 不必要的 Promise 包装fetch(`/api/users/${userId}`) // fetch 本身返回 Promise.then(response => response.json()).then(data => resolve(data)).catch(error => reject(error));}); }// 更好的方式 function getUserData(userId) {return fetch(`/api/users/${userId}`).then(response => {if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return response.json();}); }
-
总是添加
.catch()
:对于任何 Promise 链,都应该在末尾添加一个.catch()
来处理潜在的未捕获错误。 -
Promise.all
vsPromise.allSettled
:根据你的需求选择。如果任何一个失败都应该导致整个操作失败,使用Promise.all
。如果希望所有操作都尝试完成,并分别处理它们的结果,使用Promise.allSettled
。 -
理解微任务队列:Promise 的
.then
,.catch
,.finally
的回调会作为微任务 (microtask) 被放入微任务队列中,它们会在当前宏任务 (macrotask) 执行完毕后、下一个宏任务开始前立即执行。这对于理解 Promise 的执行时机非常重要。
Promise 是 JavaScript 异步编程的基石,深刻理解它对于编写健壮、可维护的现代 JavaScript 应用至关重要。
相关文章:

【前端基础】Promise 详解
文章目录 什么是 Promise?为什么要使用 Promise?创建 Promise消费 Promise (使用 Promise)1. .then(onFulfilled, onRejected)2. .catch(onRejected)3. .finally(onFinally) Promise 链 (Promise Chaining)Promise 的静态方法1. Promise.resolve(value)2…...

高性能管线式HTTP请求
高性能管线式HTTP请求:原理、实现与实践 目录 高性能管线式HTTP请求:原理、实现与实践 1. HTTP管线化的原理与优势 1.1 HTTP管线化的基本概念 关键特性: 1.2 管线化的优势 1.3 管线化的挑战 2. 高性能管线式HTTP请求的实现方案 2.1 技术选型与工具 2.2 Java实现:…...
c/c++的opencv膨胀
使用 OpenCV (C) 进行图像膨胀操作详解 图像膨胀 (Dilation) 是形态学图像处理中的另一种基本操作,与腐蚀操作相对应。它通常用于填充图像中的小孔洞、连接断开的物体部分、以及加粗二值图像中的物体。本文将详细介绍膨胀的原理,并演示如何使用 C 和 Op…...
react native搭建项目
React Native 项目搭建指南 React Native 是一个使用 JavaScript 和 React 构建跨平台移动应用的框架。以下是搭建 React Native 项目的详细步骤: 1. 环境准备 安装 Node.js 下载并安装 Node.js (推荐 LTS 版本) 安装 Java Development Kit (JDK) 对于 Androi…...

【CSS】九宫格布局
CSS Grid布局(推荐) 实现代码: <!doctype html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...

Python用Transformer、Prophet、RNN、LSTM、SARIMAX时间序列预测分析用电量、销售、交通事故数据
原文链接: tecdat.cn/?p42219 在数据驱动决策的时代,时间序列预测作为揭示数据时序规律的核心技术,已成为各行业解决预测需求的关键工具。从能源消耗趋势分析到公共安全事件预测,不同领域的数据特征对预测模型的适应性提出了差异…...

java基础(面向对象进阶高级)泛型(API一)
认识泛型 泛型就等于一个标签(比如男厕所和女厕) 泛型类 只能加字符串: 把别人写好的东西,自己封装。 泛型接口 泛型方法、泛型通配符、上下限 怎么解决下面的问题? API object类 toString: equals: objects类 包装类 为什么上面的Integer爆红…...

学习心得(17--18)Flask表单
一. 认识表单:定义表单类 password2中末端的EqualTo(password)是将密码2与密码1进行验证,看是否相同 二.使用表单: 运行 如果遇到这个报错,就在该页面去添加 下面是举例: 这就是在前端的展示效…...
AI测试和敏捷测试有什么联系与区别?
AI测试与敏捷测试作为软件质量保障领域的两种重要方法,既有紧密联系也存在显著区别。以下是两者的联系与区别分析: 一、联系 共同目标:提升测试效率与质量 敏捷测试强调通过快速迭代、持续反馈和团队协作确保交付价值,而AI测试通…...

微信小程序进阶第2篇__事件类型_冒泡_非冒泡
在小程序中, 事件分为两种类型: 冒泡事件, 当一个组件上的事件被触发后,该事件会向父节点传递非冒泡事件, 当一个组件上的事件被触发后, 该事件不会向父节点传递。 一 冒泡事件 tap, touchst…...

电机控制学习笔记
文章目录 前言一、电机二、编码器三、开环控制和闭环控制总结 前言 学习了解电机控制技术的一些原理和使用的方法。 一、电机 直流有刷电机 操作简单 使用H桥驱动直流有刷电机 直流有刷电机驱动板 电压检测 电流检测以及温度检测 直流无刷电机 使用方波或者正弦波进行换向…...
什么是前端工程化?它有什么意义
前端工程化是指通过工具、流程和规范,将前端开发从手工化、碎片化的模式转变为系统化、自动化和标准化的生产过程。其核心目标是 提升开发效率、保障代码质量、增强项目可维护性,并适应现代复杂 Web 应用的需求。 一、前端工程化的核心内容 1. 模块化开发 代码模块化:使用 …...

企业网站架构部署与优化-Nginx性能调优与深度监控
目录 #1.1Nginx性能调优 1.1.1更改进程数与连接数 1.1.2静态缓存功能设置 1.1.3设置连接超时 1.1.4日志切割 1.1.5配置网页压缩 #2.1nginx的深度监控 2.1.1GoAccess简介 2.1.2nginx vts简介 1.1Nginx性能调优 1.1.1更改进程数与连接数 (1)进程数 进程数…...

行列式的线性性质(仅限于单一行的加法拆分)
当然可以,以下是经过排版优化后的内容,保持了原始内容不变,仅调整了格式以提升可读性: 行列式的线性性质(加法拆分) 这个性质说的是:如果行列式的某一行(或某一列)的所有…...

JAVA基础编程练习题--50道
一:循环结构 1.1 for循环 水鲜花数 (1)题目 (2)难点 如何获取三位数的个位数 如何计算一个数的立方 判断两数值是否相等 (3)代码 最大公约数 (1)题目 (2&…...

leetcode 93. Restore IP Addresses
题目描述 93. Restore IP Addresses 代码 回溯法 class Solution {vector<string> res; public:vector<string> restoreIpAddresses(string s) {string IP;int part 0;backtracking(s,0,IP,part);return res;}void backtracking(const string &s,int start…...
【东枫科技】基于Docker,Nodejs,GitSite构建一个KB站点
Docker 安装桌面版本,安装Node镜像 运行node镜像 需求 和外部的某个文件夹地址可以绑定端口可以绑定,方便server的访问 docker run -itd --name node-test -v C:/Users/fs/Documents/GitHub:/home/node -p 3000:3000 node进入终端 docker exec -it …...

pytest+allure+allure-pytest 报告输出遇到的问题汇总
文章目录 前言问题一:module allure has no attribute severity_level问题二:ERROR:file or directory not found: ‐vs问题三:生成的 html 报告是空的,明明有测试用例执行完成,但报告没有显示数据 前言 pytestallure…...
Python基础语法(十四):Python常用内置模块及功能
Python标准库提供了丰富的内置模块,无需额外安装即可使用。以下是按功能分类的常用内置模块及其核心功能: 一、文件与操作系统交互 1. os 模块 功能:操作系统接口常用方法:os.getcwd() # 获取当前工作目录 os.listdir() …...

【Opencv+Yolo】_Day1图像基本处理
目录 一、计算机中的视觉: 二、Opencv基本操作: 图片基础处理: 视频基本处理: 图像截取(截取,合并,只保留一个元素) 图像填充 数值计算 图像融合 阈值判断 图像平滑 图像腐…...
MySQL各种日志类型介绍
概述 MySQL 提供了多种日志类型,用于记录数据库的运行状态、操作历史和错误信息等,这些日志对于故障排查、性能优化、安全审计和数据恢复等具有重要作用。以下是 MySQL 中常见的日志类型及其详细介绍资料已经分类整理好:https://pan.quark.c…...
15.2【基础项目】使用 TypeScript 实现密码显示与隐藏功能
在现代 Web 应用中,允许用户切换密码的可见性不仅提升了用户体验,也让表单填写更便捷。使用 TypeScript 来实现这个功能,不仅具备强类型检查优势,还能提升代码的可维护性。 ✨ 我们要实现的功能 在这篇文章中,我们将…...
Django压缩包形式下载文件
通过web将minio上的文件以压缩包-文件夹-文件的形式下载到本地 import os from bx_mes import settings from io import BytesIO import zipfile from django.http import StreamingHttpResponse class FileRemote(GenericAPIView):def post(self,request):# 压缩包名folder_n…...
晚期NSCLC临床试验终点与分析策略
1. 案例背景 1.1 研究设计 1.1.1 适应症与分组 晚期非小细胞肺癌一线治疗,干预组为新型免疫检查点抑制剂联合化疗,对照组为化疗单药,随机双盲安慰剂对照III期试验。 1.1.2 目标框架 基于FDA或ICH指南,终点定义和分析策略影响试验科学性及监管审评。 2. 终点定义 2.1 主要…...

从比分滚动到数据革命:体育数据如何重构我们的观赛体验?
当凌晨三点的欧冠决赛与闹钟冲突时,当世界杯小组赛因时差难以全程跟进时,当代体育迷早已不再依赖电视直播 —— 打开手机里的比分网,实时跳动的体育大数据正构建着全新的观赛宇宙。这些曾经被视为 "辅助工具" 的平台,如…...

华为网路设备学习-23(路由器OSPF-LSA及特殊详解 二)
OSPF动态路由协议要求: 1.必须有一个骨干区域(Area 0)。有且仅有一个,而且连续不可分割。 2.所有非骨干区域(Area 1-n)必须和骨干区域(Area 0)直接相连,且所有区域之间…...

VPet虚拟桌宠,一款桌宠软件,支持各种互动投喂等. 开源免费并且支持创意工坊
📌 大家好,我是智界工具库,每天分享好用实用且智能的开源项目,以及在JAVA语言开发中遇到的问题,如果本篇文章对您有所帮助,请帮我点个小赞小收藏小关注吧,谢谢喲!😘 工具…...

新书速览|ASP.NET MVC高效构建Web应用
《ASP.NET MVC高效构建Web应用》 本书内容 《ASP.NET MVC高效构建Web应用》以目前流行的ASP.NET MVC 5、HTML和Razor为主线,全面系统地介绍ASP.NET MVC Web应用开发的方法,配套提供实例源码、PPT课件与作者一对一QQ答疑服务。 《ASP.NET MVC高效构建Web…...

MySQL 9.3 超详细下载安装教程(Windows版)附图文说明
MySQL 9.3 超详细下载安装教程(Windows版)附图文说明 💡 本文适用于Windows 10/11系统,包含完整的安装流程、环境配置和疑难解答。建议收藏备用! 一、下载MySQL 1. 访问官网 进入MySQL官方下载页面:http…...

Linux之软件包管理器(CentOS系统) —— yum
目录 一、软件包管理器 1-1什么是软件包 1-2 Linux软件生态 Linux下载软件的过程(Ubuntu、Centos、other) 操作系统的好坏评估---生态问题 1. 应用软件生态 2. 硬件兼容性 3. 开发者社区与开源生态 4. 商业合作与盈利模式 5. 用户粘性与使用习惯 6. 安全与合规生态 …...