当前位置: 首页 > news >正文

《异步江湖:XHR、Promise 与 Event Loop 的恩怨情仇》

XMLHttpRequest 

XMLHttpRequest(简称 XHR)是浏览器提供的一个 JavaScript 对象,用于在客户端和服务器之间发送 HTTP 请求。它是实现 AJAX(Asynchronous JavaScript and XML) 技术的核心工具,允许网页在不重新加载的情况下与服务器交换数据并更新部分页面内容。。


1. 基本用法

创建 XHR 对象

const xhr = new XMLHttpRequest();

配置请求

使用 open() 方法初始化请求:

xhr.open(method, url, async);
  • method:HTTP 方法(如 GETPOST)。

  • url:请求的目标 URL。

  • async:是否异步(默认为 true)。

示例
xhr.open('GET', 'https://api.example.com/data', true);

发送请求

使用 send() 方法发送请求:

xhr.send();
  • 对于 POST 请求,可以在 send() 中传递请求体数据:

    xhr.send(JSON.stringify({ key: 'value' }));

处理响应

通过 onreadystatechange 事件监听请求状态变化:

xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {console.log('响应数据:', xhr.responseText);}
};
 

2. XHR 对象的属性和方法

属性

属性说明
readyState请求状态:
- 0:未初始化
- 1:已打开
- 2:已发送
- 3:接收中
- 4:完成
statusHTTP 状态码(如 200、404、500)。
statusTextHTTP 状态文本(如 OKNot Found)。
responseText服务器返回的文本数据(字符串形式)。
responseXML服务器返回的 XML 数据(如果响应内容是 text/xml)。
responseType设置响应类型(如 jsontextblob)。
response根据 responseType 返回的响应数据。

方法

方法说明
open(method, url)初始化请求。
send(body)发送请求,body 是可选的请求体数据。
setRequestHeader(header, value)设置请求头(如 Content-Type)。
abort()取消请求。

3. 完整示例

GET 请求

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {console.log('响应数据:', xhr.responseText);}
};
xhr.send();

POST 请求

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/submit', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {console.log('响应数据:', xhr.responseText);}
};
xhr.send(JSON.stringify({ username: 'john', password: '123456' }));

4. 事件监听

除了 onreadystatechange,XHR 还支持以下事件:

事件说明
onload请求成功完成时触发。
onerror请求失败时触发。
onprogress请求正在处理中时触发(用于监控上传/下载进度)。
示例

xhr.onload = function() {if (xhr.status === 200) {console.log('响应数据:', xhr.responseText);}
};
xhr.onerror = function() {console.error('请求失败');
};
xhr.onprogress = function(event) {if (event.lengthComputable) {console.log(`已接收 ${event.loaded} / ${event.total} 字节`);}
};

5. 跨域请求

XHR 默认受 同源策略 限制,无法直接访问不同源的资源。可以通过以下方式解决跨域问题:

  1. CORS(跨域资源共享)
    服务器设置 Access-Control-Allow-Origin 响应头。

  2. JSONP
    通过 <script> 标签加载跨域数据(仅支持 GET 请求)。

  3. 代理服务器
    通过同源服务器转发请求。


6. 与 Fetch API 的对比

特性XMLHttpRequestFetch API
语法基于回调,代码冗长基于 Promise,语法简洁
流式数据处理不支持支持
请求取消支持(abort()支持(AbortController
兼容性支持所有浏览器(包括 IE)不支持 IE
错误处理需手动检查状态码自动处理网络错误

7.查询参数

  1. 什么是查询参数:携带额外信息给服务器,返回匹配想要的数据

  2. 查询参数原理要携带的位置和语法:http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2

  3. 所以,原生 XHR 需要自己在 url 后面携带查询参数字符串,没有 axios 帮助我们把 params 参数拼接到 url 字符串后面了

特性XMLHttpRequestAxios
语法需要手动拼接 URL 或使用 URLSearchParams提供 params 配置项,自动处理查询参数
代码复杂度代码冗长,需手动处理细节代码简洁,封装了底层细节
错误处理需手动检查状态码和错误基于 Promise,支持 catch 捕获错误
兼容性支持所有浏览器(包括 IE)不支持 IE
功能扩展功能有限,需自行封装提供拦截器、请求取消等高级功能

Promise

1. 什么是 Promise?

Promise 是 JavaScript 提供的一种用于 处理异步操作 的对象。它用于解决 回调地狱 问题,使异步代码更易读、可维护。

Promise 对象表示一个 尚未完成但预计会在未来完成的操作,它可以是:

  • 进行中(pending):初始状态,既没有成功也没有失败。
  • 已完成(fulfilled):操作成功,返回一个值(由 resolve() 处理)。
  • 已拒绝(rejected):操作失败,返回一个错误(由 reject() 处理)。
2. Promise 语法
const myPromise = new Promise((resolve, reject) => {setTimeout(() => {let success = true; // 模拟成功或失败if (success) {resolve("操作成功!");} else {reject("操作失败!");}}, 1000);
});// 处理 Promise 结果
myPromise.then((result) => console.log(result)) // 操作成功!.catch((error) => console.error(error)) // 操作失败!.finally(() => console.log("操作完成")); // 无论成功或失败都会执行
3. Promise 链式调用

支持多个 .then() 串联执行,避免回调地狱

new Promise((resolve) => resolve(1)).then((num) => num * 2).then((num) => num * 3).then(console.log); // 6
4. 常用 Promise 方法
方法作用
Promise.all()同时执行多个 Promise,全部成功返回数组,否则返回第一个失败的
Promise.race()返回第一个完成的 Promise(无论成功或失败)
Promise.allSettled()等待所有 Promise 结束,无论成功或失败,返回所有结果
Promise.any()返回第一个成功的 Promise,如果全部失败,则返回 AggregateError
Promise.all([Promise.resolve("A"),Promise.resolve("B"),
]).then(console.log); // ["A", "B"]
5. async/await(Promise 的语法糖)
async function fetchData() {try {let data = await new Promise((resolve) => setTimeout(() => resolve("数据返回"), 1000));console.log(data); // 数据返回} catch (error) {console.error(error);}
}fetchData();

6.myAxios制作

基于 Promise 和 XHR 封装 myAxios 函数
核心语法:
function myAxios(config) {return new Promise((resolve, reject) => {// XHR 请求// 调用成功/失败的处理程序})
}myAxios({url: '目标资源地址'
}).then(result => {}).catch(error => {})
步骤:
 
  1. 定义 myAxios 函数,接收配置对象,返回 Promise 对象

  2. 发起 XHR 请求,默认请求方法为 GET

  3. 调用成功/失败的处理程序

  4. 使用 myAxios 函数,获取省份列表展示

整体代码:
function myAxios({ url, method = "GET", data = null, headers = {}, timeout = 5000 }) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.open(method.toUpperCase(), url, true);xhr.timeout = timeout; // 设置超时时间// 设置请求头for (let key in headers) {xhr.setRequestHeader(key, headers[key]);}// 监听请求完成事件xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {try {const responseData = JSON.parse(xhr.responseText); // 解析 JSON 数据resolve(responseData);} catch (error) {reject("JSON 解析失败");}} else {reject(`请求失败,状态码:${xhr.status}`);}}};// 监听错误xhr.onerror = function () {reject("网络错误");};// 监听超时xhr.ontimeout = function () {reject("请求超时");};// 发送请求if (method.toUpperCase() === "GET" || data === null) {xhr.send();} else {xhr.setRequestHeader("Content-Type", "application/json");xhr.send(JSON.stringify(data));}});
}

同步代码和异步代码的区别

1. 同步代码(Synchronous)

同步代码按 顺序执行,当前任务完成后才执行下一个任务。如果某个任务耗时较长(如文件读取、网络请求等),整个程序都会被 阻塞

示例:
console.log("任务 1");
console.log("任务 2");
console.log("任务 3");

执行顺序:

任务 1
任务 2
任务 3

遇到阻塞的情况

console.log("开始");
for (let i = 0; i < 1e9; i++) {} // 模拟耗时操作
console.log("结束");

如果 for 循环运行了 3 秒,那么程序会 卡 3 秒,直到循环结束才继续执行后面的代码。


2. 异步代码(Asynchronous)

异步代码不会阻塞程序,它 不会等待任务完成,而是继续执行后续代码,等任务完成后再 通知(回调、Promise、async/await)

示例(setTimeout 异步执行):
console.log("任务 1");
setTimeout(() => console.log("任务 2(延迟 1 秒)"), 1000);
console.log("任务 3");

执行顺序:

任务 1
任务 3
任务 2(延迟 1 秒后执行)

👉 异步任务(setTimeout)不会阻塞后续代码的执行。


3. 常见的异步操作

  • 定时器(setTimeout, setInterval)
  • DOM 事件(click, input, scroll)
  • 网络请求(fetch, XMLHttpRequest, axios)
  • 文件读取(fs.readFile - Node.js)
  • 数据库操作(MongoDB, MySQL)
回调函数(Callback)
function fetchData(callback) {setTimeout(() => {callback("数据加载完成");}, 1000);
}console.log("开始请求数据");
fetchData((data) => console.log(data));
console.log("代码执行完毕");

执行顺序

开始请求数据
代码执行完毕
数据加载完成(1 秒后)

4. 现代异步方案

(1)Promise
开始请求数据
代码执行完毕
数据加载完成(1 秒后)

执行顺序

开始请求数据
代码执行完毕
数据加载完成(1 秒后)
(2)async/await
 
async function fetchData() {return new Promise((resolve) => {setTimeout(() => resolve("数据加载完成"), 1000);});
}async function main() {console.log("开始请求数据");let data = await fetchData();console.log(data);console.log("代码执行完毕");
}main();

执行顺序

开始请求数据
数据加载完成(1 秒后)
代码执行完毕

👉 await 让异步代码看起来像同步代码,增强可读性。


5. 总结

对比项同步代码异步代码
执行方式按顺序执行先执行后续代码,任务完成后再执行回调
是否阻塞是(遇到耗时任务会卡住)否(不会影响后续代码执行)
使用场景计算、变量赋值、DOM 操作等I/O 操作、网络请求、定时任务等
实现方式普通代码回调函数、Promise、async/await

Promise 链式调用

Promise.then() 方法会返回一个新的 Promise,这样就可以链式调用多个 .then(),实现 异步流程控制,避免回调地狱。

1. 基本链式调用

每个 .then() 处理上一个 .then() 返回的值:

new Promise((resolve) => {setTimeout(() => resolve(1), 1000); // 1秒后返回 1
}).then((num) => {console.log(num); // 1return num * 2;}).then((num) => {console.log(num); // 2return num * 3;}).then((num) => {console.log(num); // 6return num * 4;}).then(console.log); // 24

 ✅ 执行顺序

1
2
6
24

👉 每个 .then()

2. 链式调用处理异步操作

如果 .then() 返回一个 Promise,下一个 .then() 会等待这个 Promise 解析完成:

都返回一个新的值,供下一个 .then() 使用

new Promise((resolve) => {setTimeout(() => resolve("数据 1"), 1000);
}).then((data) => {console.log(data);return new Promise((resolve) => setTimeout(() => resolve("数据 2"), 1000));}).then((data) => {console.log(data);return new Promise((resolve) => setTimeout(() => resolve("数据 3"), 1000));}).then(console.log);

执行顺序(每步间隔 1 秒)

数据 1
数据 2
数据 3

👉 每个 .then() 返回一个 Promise,下一个 .then() 需等待前一个 Promise 解析完成

3. 处理异常

链式调用中,catch() 捕获前面所有 Promise 的错误:

new Promise((resolve, reject) => {setTimeout(() => reject("出错了!"), 1000);
}).then((data) => {console.log("不会执行", data);return "继续";}).catch((error) => {console.error("捕获错误:", error);return "错误已处理"; // catch() 可以返回新值}).then(console.log); // "错误已处理"

执行顺序

捕获错误: 出错了!
错误已处理

👉 catch() 捕获错误后,链式调用不会中断,后续 .then() 仍会执行

4. finally()

无论 Promise 成功或失败finally() 都会执行

new Promise((resolve, reject) => {setTimeout(() => reject("失败了"), 1000);
}).then(console.log).catch(console.error).finally(() => console.log("操作完成"));

 ✅ 执行顺序

失败了
操作完成

👉 finally() 适合做清理操作,比如关闭加载动画等

方法作用
.then()处理成功结果,可链式调用
.catch()处理 Promise 失败(捕获错误)
.finally()无论成功或失败都会执行

JavaScript 事件循环(Event Loop)

1. 什么是事件循环?

JavaScript 是 单线程 的,它使用 事件循环(Event Loop) 机制来执行同步和异步代码,确保不会阻塞主线程。

  • 同步任务:立即执行,放入 主线程(调用栈 Call Stack) 运行。
  • 异步任务:放入 任务队列(Task Queue),等主线程空闲后执行。

2. 事件循环执行流程

  1. 执行同步代码(放在主线程)。
  2. 遇到异步任务(如 setTimeoutPromisefetch,将它交给 Web APIs 处理。
  3. 同步代码执行完毕后,检查任务队列
    • 微任务队列(Microtask Queue):执行 Promise.then()queueMicrotask()MutationObserver
    • 宏任务队列(Macrotask Queue):执行 setTimeoutsetIntervalsetImmediate(Node.js)、I/O 任务等。
  4. 先执行所有微任务,再执行宏任务,然后进入下一个循环。

3. 示例解析

示例 1:基本事件循环
 
console.log("同步 1");setTimeout(() => console.log("setTimeout"), 0);Promise.resolve().then(() => console.log("Promise 1"));console.log("同步 2");

执行顺序

 
同步 1
同步 2
Promise 1  (微任务)
setTimeout  (宏任务)

📌 解释

  1. 同步 1、同步 2:立即执行。
  2. Promise微任务,优先执行。
  3. setTimeout宏任务,等微任务执行完才运行。

示例 2:多个宏任务和微任务
 
console.log("同步 1");setTimeout(() => console.log("setTimeout 1"), 0);
setTimeout(() => console.log("setTimeout 2"), 0);Promise.resolve().then(() => {console.log("Promise 1");return Promise.resolve();
}).then(() => console.log("Promise 2"));console.log("同步 2");

执行顺序

 
同步 1
同步 2
Promise 1  (微任务)
Promise 2  (微任务)
setTimeout 1  (宏任务)
setTimeout 2  (宏任务)

📌 解释

  1. 同步代码 先执行("同步 1" → "同步 2")。
  2. Promise 微任务 依次执行("Promise 1" → "Promise 2")。
  3. setTimeout 宏任务 最后执行("setTimeout 1" → "setTimeout 2")。

示例 3:复杂情况
 
console.log("A");setTimeout(() => {console.log("B");Promise.resolve().then(() => console.log("C"));
}, 0);Promise.resolve().then(() => console.log("D"));console.log("E");

执行顺序

 
A
E
D   (微任务)
B   (宏任务)
C   (B 里的微任务)

📌 解释

  1. 执行同步代码:"A"、"E"。
  2. Promise 微任务:"D" 先执行。
  3. setTimeout 宏任务:"B" 进入队列,等同步 & 微任务执行完毕后运行。
  4. "B" 里面的 Promise(C)微任务,执行优先级高于新的宏任务。

Promise.all() 静态方法

Promise.all() 用于 并行执行多个异步任务,并且 等待所有 Promise 都成功,才会返回 所有结果。如果 任何一个 Promise 失败Promise.all() 立即 reject,不会等待其他任务完成。

1. 基本用法

 
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);Promise.all([p1, p2, p3]).then((results) => {console.log(results); // [1, 2, 3]
});

执行顺序

 
[1, 2, 3]

📌 解释

  • Promise.all() 需要 等待所有 Promise 解析,返回 [1, 2, 3]

2. 异步任务示例

 
const p1 = new Promise((resolve) => setTimeout(() => resolve("数据 1"), 1000));
const p2 = new Promise((resolve) => setTimeout(() => resolve("数据 2"), 2000));
const p3 = new Promise((resolve) => setTimeout(() => resolve("数据 3"), 3000));console.log("开始请求");Promise.all([p1, p2, p3]).then((results) => {console.log("所有数据加载完成:", results);
});

执行顺序

 
开始请求
(等待 3 秒)
所有数据加载完成: [ '数据 1', '数据 2', '数据 3' ]

📌 解释

  • Promise.all() 等待所有任务完成(最大耗时任务 3 秒)。
  • 3 秒后,返回 ["数据 1", "数据 2", "数据 3"]

3. 处理失败(任何一个失败都会触发 reject)

 
const p1 = Promise.resolve("成功 1");
const p2 = Promise.reject("失败 2");
const p3 = Promise.resolve("成功 3");Promise.all([p1, p2, p3]).then(console.log).catch((error) => console.error("发生错误:", error));

执行顺序

 
发生错误: 失败 2

📌 解释

  • p2 失败,Promise.all 立即 reject,不会等待 p3

4. 结合 map() 批量请求

📌 批量请求 5 个 API

 
const urls = ["https://jsonplaceholder.typicode.com/todos/1","https://jsonplaceholder.typicode.com/todos/2","https://jsonplaceholder.typicode.com/todos/3",
];Promise.all(urls.map((url) => fetch(url).then((res) => res.json()))).then(console.log).catch(console.error);

执行结果

 
[{ "userId": 1, "id": 1, "title": "...", "completed": false },{ "userId": 1, "id": 2, "title": "...", "completed": false },{ "userId": 1, "id": 3, "title": "...", "completed": false }
]

📌 解释

  • map() 遍历 URL 数组,创建 fetch() 请求。
  • Promise.all() 并行执行所有请求,加速响应。

5. 解决 Promise.all() 失败问题

如果希望即使某些 Promise 失败,仍然获得结果,可以使用 Promise.allSettled()

 
const p1 = Promise.resolve("成功 1");
const p2 = Promise.reject("失败 2");
const p3 = Promise.resolve("成功 3");Promise.allSettled([p1, p2, p3]).then(console.log);

执行结果

 
[{ "status": "fulfilled", "value": "成功 1" },{ "status": "rejected", "reason": "失败 2" },{ "status": "fulfilled", "value": "成功 3" }
]

📌 解释

  • Promise.allSettled() 不会因为某个 Promise 失败而中断
  • 返回 每个 Promise 的状态(fulfilled / rejected)

总结

方法作用
Promise.all()全部成功才返回数组,任意失败立即 reject
Promise.allSettled()所有任务完成后返回数组(包含成功和失败)

 

医学、法律、商业、工程 都是崇高的追求,足以支撑人的一生。但诗歌、美丽、浪漫、爱情这些才是我们生活的意义。

相关文章:

《异步江湖:XHR、Promise 与 Event Loop 的恩怨情仇》

XMLHttpRequest XMLHttpRequest&#xff08;简称 XHR&#xff09;是浏览器提供的一个 JavaScript 对象&#xff0c;用于在客户端和服务器之间发送 HTTP 请求。它是实现 AJAX&#xff08;Asynchronous JavaScript and XML&#xff09; 技术的核心工具&#xff0c;允许网页在不…...

【极客时间】浏览器工作原理与实践-2 宏观视角下的浏览器 (6讲) - 2.5 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

https://time.geekbang.org/column/article/118205 2.5 渲染流程&#xff08;上&#xff09;&#xff1a;HTML、CSS和JavaScript&#xff0c;是如何变成页面的&#xff1f; 2.4讲了导航相关的流程&#xff0c;那导航被提交后又会怎么样呢&#xff1f; 就进入了渲染阶段。 这…...

蓝桥杯第15届真题解析

由硬件框图可以知道我们要配置LED 和按键、lcd&#xff0c;解决lcd引脚冲突 LED 先配置LED的八个引脚为GPIO_OutPut&#xff0c;锁存器PD2也是&#xff0c;然后都设置为起始高电平&#xff0c;生成代码时还要去解决引脚冲突问题 按键 按键配置&#xff0c;由原理图按键所对引…...

19c rac-expdp备份异常处理

客户反馈&#xff0c;有套19c rac环境&#xff0c;补丁是19.13的&#xff0c;有1个节点使用expdp备份用户异常&#xff0c;报错如下 Connected to: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production ORA-31626: job does not exist ORA-31637: cannot…...

轻松部署 Stable Diffusion WebUI 并实现局域网共享访问:解决 Conda Python 版本不为 3.10.6 的难题

这篇博文主要为大家讲解关于sd webui的部署问题&#xff0c;大家有什么不懂的可以随时问我&#xff0c;如果没有及时回复&#xff0c;可联系&#xff1a;1198965922 如果后续大家需要了解怎么用代码调用部署好的webui的接口&#xff0c;可以在评论区留言哦&#xff0c;博主可以…...

20250304在Ubuntu20.04的GUI下格式化exFAT格式的TF卡为ext4格式

20250304在Ubuntu20.04的GUI下格式化exFAT格式的TF卡为ext4格式 2025/3/4 16:47 缘起&#xff1a;128GB的TF卡&#xff0c;只能格式化为NTFS/exFAT/ext4。 在飞凌的OK3588-C下&#xff0c;NTFS格式只读。 exFAT需要改内核来支持。 现在只剩下ext4了。 linux R4默认不支持exFAT…...

AIP-159 跨集合读

编号159原文链接AIP-159: Reading across collections状态批准创建日期2019-07-26更新日期2019-07-26 有时&#xff0c;用户需要跨集合检索资源&#xff0c;或者在不知道资源所在集合的情况下检索单个资源。 指南 API 可以 在标准 List 方法中允许用户使用 - &#xff08;连…...

C++进阶(七)--STL--bitset(位图)的介绍与基本功能模拟实现

文章目录 引入1.位图的介绍1.1位图的概念1.2位图的应用1.3bitset的基本使用bitset的定义方式bitset成员函数的使用 2.位图的基本模拟实现2.1基本结构2.2构造函数2.3set函数2.4reset2.5test 3.位图考察题目3.1只出现⼀次的整数&#xff1f;3.2找到两个文件交集&#xff1f;3.3出…...

清北deepseek8本手册

“清北手册”通常是“清华大学和北京大学推出的DeepSeek手册”的简写。近期&#xff0c;随着AI技术的迅速发展&#xff0c;清北两高校陆续发布多本自家的DeepSeek学习手册&#xff0c;助力普通人学习进阶。 清华大学的DeepSeek手册已推出5册&#xff0c;内容丰富全面&#xff0…...

如何将Promise.then中的值直接return出来

Promise 如何返回值&#xff0c;而不是返回 Promise 对象。实际开发中使用封装好的异步请求函数&#xff0c;为什么调用该函数返回的值一直都是 undefined。 一、需求 定义一个 foo 函数&#xff0c;在里面执行异步操作&#xff0c;然后取得 Promise.then 中的值并 return 出来…...

利用golang embed特性嵌入前端资源问题解决

embed嵌入前端资源&#xff0c;配置前端路由的代码如下 func StartHttpService(port string, assetsFs embed.FS) error {//r : gin.Default()gin.SetMode(gin.ReleaseMode)r : gin.New()r.Use(CORSMiddleware())// 静态文件服务dist, err : fs.Sub(assetsFs, "assets/di…...

SPI驱动(二) -- SPI驱动程序模型

文章目录 参考资料&#xff1a;一、SPI驱动重要数据结构1.1 SPI控制器数据结构1.2 SPI设备数据结构1.3 SPI驱动数据结构 二、SPI 驱动框架2.1 SPI控制器驱动程序2.2 SPI设备驱动程序 三、总结 参考资料&#xff1a; 内核头文件&#xff1a;include\linux\spi\spi.h 一、SPI驱…...

【无标题】FrmImport

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;四、项目展示五、资源链接 前言 我能抽象出整个世界&#xff0c;但是我不能抽象你。 想让你成为私有常量&#xff0c;这样外部函数就无法访问你。 又想让你成为全局常量&#xff0c;这样在我的…...

深入浅出 Go 语言:协程(Goroutine)详解

深入浅出 Go 语言&#xff1a;协程(Goroutine)详解 引言 Go 语言的协程&#xff08;goroutine&#xff09;是其并发模型的核心特性之一。协程允许你轻松地编写并发代码&#xff0c;而不需要复杂的线程管理和锁机制。通过协程&#xff0c;你可以同时执行多个任务&#xff0c;并…...

vLLM代码推理Qwen2-VL多模态

由于近期代码微调以及测试都是在远程服务器上&#xff0c;因此LLamafactory-cli webui 以及vLLM的ui均无法使用&#xff0c;因此不断寻求解决方案&#xff0c;我提供一个解决方案&#xff0c;LLamafactory微调完成的模型需要合并为一个完整模型后再使用vLLM进行代码推理测试微调…...

DNS云解析有什么独特之处?

在数字化浪潮中&#xff0c;每一次网页点击、视频加载或在线交易背后&#xff0c;都依赖着域名系统&#xff08;DNS&#xff09;的高效运转。传统DNS架构的局限性&#xff08;如单点故障、延迟高、安全脆弱&#xff09;在云计算时代被彻底颠覆&#xff0c;DNS云解析作为新一代解…...

视频流畅播放相关因素

视频播放的流畅度是一个综合性问题&#xff0c;涉及从视频文件本身到硬件性能、网络环境、软件优化等多个环节。以下是影响流畅度的关键因素及优化建议&#xff1a; 一、视频文件本身 1. 分辨率与帧率 1.问题&#xff1a;高分辨率&#xff08;如4K&#xff09;或高帧率&#…...

Python实现一个类似MybatisPlus的简易SQL注解

文章目录 前言实现思路定义一个类然后开始手撸这个微型框架根据字符串获取到所定义的DTO类构建返回结果装饰器解析字符串&#xff0c;获得变量SQL字符串拼接 使用装饰器 前言 在实际开发中&#xff0c;根据业务拼接SQL所需要考虑的内容太多了。于是&#xff0c;有没有一种办法…...

linux一些使用技巧

linux一些使用技巧 文件名称和路径的提取切换用户执行当前脚本一行演示单引号与双引号的使用curl命令仅输出响应头信息,不输出body体文件名称和路径的提取 文件路径为 /tmp/tkgup/test.sh 方式获取文件名获取文件路径获取文件全路径方式一basename ${file}dirname ${file}real…...

小模型和小数据可以实现AGI吗

小模型和小数据很难实现真正的 通用人工智能&#xff08;AGI, Artificial General Intelligence&#xff09;&#xff0c;但在特定任务或受限环境下&#xff0c;可以通过高效的算法和优化方法实现“近似 AGI” 的能力。 1. 为什么小模型小数据难以实现 AGI&#xff1f; AGI 需…...

用Circuit JS在线模拟器,5分钟搞定欧姆定律和LRC振荡电路实验

用Circuit JS在线模拟器&#xff0c;5分钟搞定欧姆定律和LRC振荡电路实验 在电子工程和物理教学中&#xff0c;理论公式与实验验证的结合一直是提升学习效率的关键。传统实验室受限于设备、场地和时间&#xff0c;而Circuit JS这款基于浏览器的开源电路模拟器&#xff0c;恰好填…...

深入STM32中断系统:从EXTI触发到NVIC裁决的完整流程剖析(附流程图详解)

深入STM32中断系统&#xff1a;从EXTI触发到NVIC裁决的完整流程剖析 在嵌入式开发中&#xff0c;中断系统是实时响应的核心机制。对于STM32开发者而言&#xff0c;深入理解从外部信号触发到CPU执行中断服务程序(ISR)的完整链路&#xff0c;是优化系统实时性、排查异常问题的关…...

使用Taotoken后我们如何清晰观测各模型的用量与延迟表现

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用Taotoken后我们如何清晰观测各模型的用量与延迟表现 当团队在项目中同时接入多个大语言模型时&#xff0c;一个常见的困扰随之…...

JetBrains IDE试用期重置终极指南:三步实现无限开发体验

JetBrains IDE试用期重置终极指南&#xff1a;三步实现无限开发体验 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 还在为JetBrains IDE试用期到期而烦恼吗&#xff1f;ide-eval-resetter是你的理想解决方案&…...

人肝非实质细胞(NPC)详解:Kupffer Cells、HSCs与LSECs如何重建真实肝脏微环境并提升NASH与ADME-Tox研究准确性

摘要&#xff1a;传统单一肝细胞模型在药物肝毒性评价、NASH机制研究以及肝纤维化研究中&#xff0c;长期存在体外快速去分化、病理表型不完整以及与临床结果偏差较大的问题。近年来&#xff0c;人肝非实质细胞&#xff08;Hepatic Non-Parenchymal Cells&#xff0c;NPC&#…...

Linux密钥文件管理排查方法

Linux密钥文件管理排查方法本文面向具备一定 Linux 基础的技术人员&#xff0c;围绕密钥文件管理展开&#xff0c;重点讨论敏感文件权限、轮换流程和审计追踪。在中级运维和系统管理工作中&#xff0c;这类主题常常与配置变更、资源状态、权限边界、自动化任务和业务影响交织在…...

《数据挖掘》读书笔记系列(一):大数据时代与数据挖掘概述

---title: 《数据挖掘》读书笔记系列&#xff08;一&#xff09;&#xff1a;大数据时代与数据挖掘概述categories: 数据挖掘tags: 数据挖掘, 机器学习, 读书笔记cover: ---## &#x1f4da; 关于本书> **书名**&#xff1a;《数据挖掘》 > **作者**&#xff1a;吕欣>…...

科技赋能林草防火,合规筑牢生态屏障—— 杭兴智能 XHJK‑5000 / HXJK‑6000 系列智慧宣传杆适配 LY/T 2798‑2025 标准实践

森林草原是我国重要的生态资源&#xff0c;守护林草安全、防范火灾风险&#xff0c;是生态文明建设的关键一环。随着《森林草原防灭火条例》深入实施与林业行业标准化建设持续推进&#xff0c;传统人工巡护、静态标语、零散警示等方式&#xff0c;已难以满足新时期 “预防为主、…...

Altium Designer 22 导出嘉立创SMT文件保姆级教程(附BOM/坐标文件避坑指南)

Altium Designer 22 导出嘉立创SMT文件全流程解析与实战技巧 在电子设计领域&#xff0c;从手工焊接转向SMT贴片生产是一个关键的进阶步骤。对于使用Altium Designer&#xff08;简称AD&#xff09;的设计师来说&#xff0c;掌握正确的文件导出方法不仅能节省大量时间&#xff…...

护眼钢化膜是智商税?圆偏振光+AR降反射实测,观复盾用硬核技术给出答案

护眼钢化膜是智商税&#xff1f;圆偏振光AR降反射实测&#xff0c;观复盾用硬核技术给出答案“花上百块买的护眼钢化膜&#xff0c;贴上后屏幕又黄又暗&#xff0c;眼睛反而更累了。”这样的抱怨在数码社区里比比皆是。与此同时&#xff0c;也有用户表示换了圆偏振光膜后&#…...