【大前端系列19】JavaScript核心:Promise异步编程与async/await实践

JavaScript核心:Promise异步编程与async/await实践

系列: 「全栈进化:大前端开发完全指南」系列第19篇
核心: 深入理解Promise机制与async/await语法,掌握现代异步编程技术

📌 引言

在JavaScript的世界中,异步编程是无法回避的核心概念。从最早的回调函数,到Promise的出现,再到ES7中async/await语法的引入,JavaScript的异步编程模式经历了显著的演变。这些变化不仅提升了代码的可读性和可维护性,也让复杂异步流程的控制变得更加直观和优雅。

异步编程之所以重要,是因为JavaScript作为单线程语言,需要高效处理诸如网络请求、文件读写、定时器等不阻塞主线程的操作。掌握现代异步编程技术,对构建响应式、高性能的Web应用至关重要。

本文将带你:

  • 理解Promise的设计理念与内部实现原理
  • 掌握Promise链式调用与错误处理的最佳实践
  • 深入理解async/await语法糖的本质
  • 探索Promise的高级应用模式与性能优化策略
  • 手写Promise核心功能,加深理解
  • 通过实战案例,应用所学知识解决实际问题

无论你是刚刚接触Promise的新手,还是想深入理解异步编程原理的资深开发者,本文都将为你提供系统而深入的指导。

📌 Promise基础

2.1 从回调地狱到Promise

在Promise出现之前,JavaScript处理异步操作主要依赖回调函数,这种方式在处理多层嵌套的异步操作时,会导致所谓的"回调地狱"(Callback Hell):

getData(function(data) {getMoreData(data, function(moreData) {getEvenMoreData(moreData, function(evenMoreData) {getFinalData(evenMoreData, function(finalData) {// 终于拿到最终数据,但代码已经深度嵌套console.log('Got the final data:', finalData);}, handleError);}, handleError);}, handleError);
}, handleError);

这种代码不仅难以阅读和维护,错误处理也变得复杂。Promise通过提供更结构化的方式来处理异步操作,解决了这些问题:

getData().then(data => getMoreData(data)).then(moreData => getEvenMoreData(moreData)).then(evenMoreData => getFinalData(evenMoreData)).then(finalData => {console.log('Got the final data:', finalData);}).catch(error => {// 统一处理错误handleError(error);});

2.2 Promise的状态与生命周期

Promise是一个代表异步操作最终完成或失败的对象。它有三种状态:

  1. pending(进行中):初始状态,既不是成功也不是失败
  2. fulfilled(已成功):操作成功完成
  3. rejected(已失败):操作失败

Promise状态的转换是单向的,一旦从pending转变为fulfilled或rejected,状态就不再改变。这种特性确保了Promise的稳定性和可预测性。

Promise状态转换

2.3 Promise的基本用法

Promise构造函数接收一个执行器函数,该函数接受两个参数:resolvereject

const promise = new Promise((resolve, reject) => {// 异步操作if (/* 操作成功 */) {resolve(value); // 成功,传递结果} else {reject(error); // 失败,传递错误}
});promise.then(value => {// 处理成功结果}).catch(error => {// 处理错误}).finally(() => {// 无论成功失败都会执行});

Promise提供了以下核心方法:

  • then(onFulfilled, onRejected):注册成功和失败回调
  • catch(onRejected):注册失败回调,相当于then(null, onRejected)
  • finally(onFinally):注册一个总是会执行的回调,无论Promise成功或失败

2.4 手写简易Promise实现

为了深入理解Promise的工作原理,我们可以实现一个符合Promises/A+规范的简易版Promise:

class MyPromise {static PENDING = 'pending';static FULFILLED = 'fulfilled';static REJECTED = 'rejected';constructor(executor) {this.status = MyPromise.PENDING;this.value = undefined;this.reason = undefined;this.onFulfilledCallbacks = [];this.onRejectedCallbacks = [];const resolve = value => {if (this.status === MyPromise.PENDING) {this.status = MyPromise.FULFILLED;this.value = value;this.onFulfilledCallbacks.forEach(callback => callback(this.value));}};const reject = reason => {if (this.status === MyPromise.PENDING) {this.status = MyPromise.REJECTED;this.reason = reason;this.onRejectedCallbacks.forEach(callback => callback(this.reason));}};try {executor(resolve, reject);} catch (error) {reject(error);}}then(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };// 创建新的Promise以支持链式调用const promise2 = new MyPromise((resolve, reject) => {if (this.status === MyPromise.FULFILLED) {setTimeout(() => {try {const x = onFulfilled(this.value);this.resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}}, 0);}if (this.status === MyPromise.REJECTED) {setTimeout(() => {try {const x = onRejected(this.reason);this.resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}}, 0);}if (this.status === MyPromise.PENDING) {this.onFulfilledCallbacks.push(value => {setTimeout(() => {try {const x = onFulfilled(value);this.resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}}, 0);});this.onRejectedCallbacks.push(reason => {setTimeout(() => {try {const x = onRejected(reason);this.resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}}, 0);});}});return promise2;}catch(onRejected) {return this.then(null, onRejected);}// 处理Promise解析过程resolvePromise(promise, x, resolve, reject) {if (promise === x) {reject(new TypeError('Chaining cycle detected for promise'));return;}let called = false;if (x !== null && (typeof x === 'object' || typeof x === 'function')) {try {const then = x.then;if (typeof then === 'function') {then.call(x,value => {if (called) return;called = true;this.resolvePromise(promise, value, resolve, reject);},reason => {if (called) return;called = true;reject(reason);});} else {resolve(x);}} catch (error) {if (called) return;called = true;reject(error);}} else {resolve(x);}}// 静态方法static resolve(value) {return new MyPromise(resolve => resolve(value));}static reject(reason) {return new MyPromise((_, reject) => reject(reason));}
}

上面的实现包含了Promise的核心功能:

  • 三种状态及状态转换
  • 异步支持和回调队列
  • then方法的链式调用
  • 处理返回值和异常
  • 基本的静态方法

2.5 Promise的微任务特性

Promise的回调是被推入微任务队列(Microtask Queue)执行的,而不是宏任务队列。这一点在处理异步操作顺序时非常重要:

console.log('1. 同步代码开始');setTimeout(() => {console.log('2. 宏任务(setTimeout)');
}, 0);Promise.resolve().then(() => {console.log('3. 微任务(Promise.then)');
});console.log('4. 同步代码结束');// 输出顺序:
// 1. 同步代码开始
// 4. 同步代码结束
// 3. 微任务(Promise.then)
// 2. 宏任务(setTimeout)

微任务队列的特性使得Promise可以在当前事件循环结束、下一个宏任务开始之前执行,这为异步操作提供了更好的实时性和可预测性。

📌 Promise进阶

3.1 Promise链式调用深入解析

Promise的链式调用是其最强大的特性之一。每次调用then()方法都会返回一个新的Promise对象,而不是原来的Promise:

const promise = new Promise((resolve, reject) => {resolve(1);
});const promise2 = promise.then(value => {console.log(value); // 1return value + 1;
});const promise3 = promise2.then(value => {console.log(value); // 2return value + 1;
});promise3.then(value => {console.log(value); // 3
});// promise !== promise2 !== promise3

理解链式调用的数据流转和异常传递机制是掌握Promise的关键:

  1. 返回值传递:一个Promise的then方法返回的值会被传递给下一个then方法
  2. Promise的传递:如果返回另一个Promise,将等待该Promise解决并传递其结果
  3. 异常冒泡:链中任何一环抛出的错误都会被后续的catch捕获
  4. 错误恢复catch之后可以继续then,实现错误恢复机制
fetchUser().then(user => {if (!user.isActive) {// 抛出错误,将跳过后续的then,直接进入catchthrow new Error('User not active');}return fetchUserPosts(user.id);}).then(posts => {// 处理文章return processUserPosts(posts);}).catch(error => {// 统一处理前面所有可能的错误console.error('Error:', error);// 返回一个默认值或新的Promise,继续链式调用return { posts: [] };}).then(result => {// 错误处理后的恢复流程console.log('Final result:', result);});

3.2 Promise组合器:Promise.all、Promise.race、Promise.allSettled、Promise.any

Promise提供了多种组合方法,用于处理多个Promise的协作:

Promise.all(iterable)

等待所有Promise完成,或有一个被拒绝:

const promises = [fetch('/api/users'),fetch('/api/posts'),fetch('/api/comments')
];Promise.all(promises).then(responses => {// 所有请求都成功完成return Promise.all(responses.map(res => res.json()));}).then(data => {const [users, posts, comments] = data;// 使用获取的数据console.log('Users:', users);console.log('Posts:', posts);console.log('Comments:', comments);}).catch(error => {// 只要有一个promise被拒绝,就会执行到这里console.error('Error:', error);});
Promise.race(iterable)

返回最先完成(无论成功或失败)的Promise的结果:

// 实现请求超时
function fetchWithTimeout(url, timeout) {const fetchPromise = fetch(url);const timeoutPromise = new Promise((_, reject) => {setTimeout(() => reject(new Error('Request timed out')), timeout);});return Promise.race([fetchPromise, timeoutPromise]);
}fetchWithTimeout('/api/data', 5000).then(response => response.json()).then(data => console.log('Data:', data)).catch(error => console.error('Error:', error));
Promise.allSettled(iterable)

等待所有Promise完成(无论成功或失败):

const promises = [fetch('/api/users').then(res => res.json()),fetch('/api/nonexistent').then(res => res.json()),fetch('/api/posts').then(res => res.json())
];Promise.allSettled(promises).then(results => {results.forEach((result, index) => {if (result.status === 'fulfilled') {console.log(`Promise ${index} succeeded with:`, result.value);} else {console.log(`Promise ${index} failed with:`, result.reason);}});// 筛选成功的结果const successfulResults = results.filter(result => result.status === 'fulfilled').map(result => result.value);return successfulResults;});
Promise.any(iterable)

返回第一个成功的Promise,如果都失败则返回AggregateError:

const mirrors = ['https://mirror1.example.com/file','https://mirror2.example.com/file','https://mirror3.example.com/file'
];Promise.any(mirrors.map(url => fetch(url))).then(firstSuccessfulResponse => {console.log('Downloaded from first available mirror');return firstSuccessfulResponse.blob();}).catch(error => {console.error('All downloads failed:', error);});

3.3 Promise错误处理最佳实践

Promise的错误处理需要特别注意,因为忽略错误可能导致静默失败:

// 错误的做法:未捕获Promise拒绝
fetch('/api/data').then(response => {if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return response.json();}).then(data => {console.log('Data:', data);});// 没有catch,如果发生错误,将被吞没或触发未捕获的Promise拒绝

以下是一些Promise错误处理的最佳实践:

  1. 始终添加catch处理器
promiseFunction().then(result => {// 处理结果}).catch(error => {// 处理错误console.error('Error:', error);});
  1. 在Promise链的末尾使用单一catch
fetchData().then(processData).then(saveData).then(notifyUser).catch(error => {// 统一处理任何步骤的错误handleError(error);});
  1. 区分不同的错误类型
fetchData().then(data => {// 处理数据}).catch(error => {if (error instanceof NetworkError) {// 处理网络错误} else if (error instanceof ValidationError) {// 处理验证错误} else {// 处理其他错误throw error; // 如果不能处理,可以重新抛出}});
  1. 使用finally进行清理
showLoadingIndicator();fetchData().then(data => {displayData(data);}).catch(error => {showErrorMessage(error);}).finally(() => {// 无论成功或失败,都会执行hideLoadingIndicator();});
  1. 处理未捕获的Promise拒绝
window.addEventListener('unhandledrejection', event => {console.error('Unhandled promise rejection:', event.reason);// 可以进行全局错误处理event.preventDefault(); // 防止默认处理
});

3.4 Promise性能优化

在使用Promise进行复杂异步操作时,以下优化策略可以提高应用性能:

  1. 避免Promise嵌套:使用链式调用而不是嵌套
// 不好的实践
fetch('/api/user').then(response => response.json()).then(user => {fetch(`/api/posts?userId=${user.id}`).then(response => response.json()).then(posts => {// 处理文章});});// 优化后
fetch('/api/user').then(response => response.json()).then(user => fetch(`/api/posts?userId=${user.id}`)).then(response => response.json()).then(posts => {// 处理文章});
  1. 合理使用Promise.all进行并行请求
// 串行请求(较慢)
async function fetchAllData() {const userData = await fetchUser();const postsData = await fetchPosts();const commentsData = await fetchComments();return { userData, postsData, commentsData };
}// 并行请求(较快)
async function fetchAllData() {const [userData, postsData, commentsData] = await Promise.all([fetchUser(),fetchPosts(),fetchComments()]);return { userData, postsData, commentsData };
}
  1. 优化Promise链中的计算密集型操作
fetchLargeDataSet().then(data => {// 计算密集型操作可能阻塞UIreturn processLargeData(data);}).then(result => {displayResult(result);});// 优化:使用Web Worker处理计算密集型任务
fetchLargeDataSet().then(data => {return new Promise(resolve => {const worker = new Worker('data-processor.js');worker.postMessage(data);worker.onmessage = e => {resolve(e.data);worker.terminate();};});}).then(result => {displayResult(result);});
  1. 避免不必要的Promise创建
// 不必要的Promise封装
function getValue() {return new Promise(resolve => {resolve(42); // 直接返回值的情况});
}// 优化:使用Promise.resolve
function getValue() {return Promise.resolve(42);
}// 对于已经是Promise的值,不需要再次包装
function processValue(value) {// 不好的做法return new Promise((resolve, reject) => {value.then(resolve).catch(reject);});// 更好的做法: 直接返回Promisereturn value;
}
  1. 使用Promise池控制并发数量
async function promisePool(promiseFns, poolLimit) {const results = [];const executing = new Set();async function executePromise(promiseFn, index) {const promise = promiseFn();executing.add(promise);try {const result = await promise;results[index] = result;} catch (error) {results[index] = error;} finally {executing.delete(promise);}}for (let i = 0; i < promiseFns.length; i++) {if (executing.size >= poolLimit) {await Promise.race(executing);}executePromise(promiseFns[i], i);}return Promise.all(results);
}// 使用示例
const urls = ['url1', 'url2', ..., 'url100'];
const promiseFns = urls.map(url => () => fetch(url));promisePool(promiseFns, 5) // 最多同时执行5个请求.then(results => {console.log('All requests completed');});

📌 async/await详解

4.1 async/await的基本用法

async/await是ES7中引入的一种异步编程语法,它基于Promise,提供了更简洁、直观的异步代码编写方式:

async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();return data;} catch (error) {console.error('Error:', error);return null;}
}fetchData().then(data => {console.log('Data:', data);}).catch(error => {console.error('Error:', error);});

4.2 async/await的错误处理

async/await语法中,错误处理可以通过try/catch块来实现:

async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();return data;} catch (error) {console.error('Error:', error);return null;}
}fetchData().then(data => {console.log('Data:', data);}).catch(error => {console.error('Error:', error);});

4.3 async/await的并发控制

async/await语法可以很方便地实现并发控制,例如:

async function fetchAllData() {const [userData, postsData, commentsData] = await Promise.all([fetch('/api/users').then(res => res.json()),fetch('/api/posts').then(res => res.json()),fetch('/api/comments').then(res => res.json())]);return { userData, postsData, commentsData };
}fetchAllData().then(data => {console.log('Users:', data.userData);console.log('Posts:', data.postsData);console.log('Comments:', data.commentsData);}).catch(error => {console.error('Error:', error);});

📌 异步函数实战

5.1 异步函数与Promise的结合

async/await语法可以与Promise无缝结合,例如:

async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();return data;} catch (error) {console.error('Error:', error);return null;}
}fetchData().then(data => {console.log('Data:', data);}).catch(error => {console.error('Error:', error);});

5.2 异步函数与生成器的结合

async/await语法可以与生成器函数结合使用,例如:

async function* fetchData() {try {const response = await fetch('/api/data');const data = await response.json();yield data;} catch (error) {console.error('Error:', error);return null;}
}const dataIterator = fetchData();dataIterator.next().then(result => {if (!result.done) {console.log('Data:', result.value);}}).catch(error => {console.error('Error:', error);});

📌 总结与展望

6.1 异步编程范式的演进

JavaScript异步编程经历了几个主要阶段的演进:

  1. 回调函数:最早的异步处理方式,简单但容易形成回调地狱
  2. Promise:引入了更结构化的异步处理方案,支持链式调用和更好的错误处理
  3. Generators:允许暂停和恢复函数执行,为异步编程提供了新思路
  4. async/await:在Promise基础上提供更简洁、直观的语法,使异步代码更接近同步风格

这一演进过程体现了JavaScript作为一门语言在处理异步操作方面的不断成熟和优化。

6.2 核心要点回顾

通过本文,我们深入了解了Promise和async/await的工作原理和最佳实践:

  1. Promise的核心机制:状态转换、链式调用、错误传播
  2. Promise的高级应用:组合器方法、错误处理、性能优化
  3. async/await的工作原理:基于Promise和生成器的语法糖
  4. async/await的最佳实践:错误处理、并发控制、陷阱避免
  5. 实战应用:构建可靠的数据服务和任务管理系统

6.3 未来发展趋势

异步编程领域还在不断发展,以下是一些值得关注的趋势:

  1. 响应式编程:通过Observable等模式处理数据流和事件
  2. 并发原语:SharedArrayBuffer、Atomics等提供更底层的并发控制
  3. Worker线程:Web Workers和Worker Threads (Node.js)提供真正的多线程能力
  4. 异步迭代器for await...of语法用于处理异步数据流
  5. 顶层await:在模块顶层使用await,无需async函数包装

6.4 应用建议与最佳实践总结

在实际开发中,我们推荐以下最佳实践:

  1. 优先使用async/await处理主要业务逻辑,代码更清晰易读
  2. 善用Promise.all等方法进行并行处理,提高性能
  3. 始终添加完善的错误处理,避免未捕获的Promise拒绝
  4. 考虑请求超时和重试机制,提升应用可靠性
  5. 合理使用缓存,减少不必要的网络请求
  6. 注意内存泄漏问题,不要在Promise链中持有不再需要的大对象引用
  7. 使用合适的抽象层,如本文的数据服务模块,提高代码可维护性

掌握这些现代JavaScript异步编程技术,将帮助你构建更高效、可靠和易维护的Web应用。

参考资料

  1. MDN Web Docs - Promise
  2. MDN Web Docs - async function
  3. JavaScript Info - Promise
  4. JavaScript Info - Async/await
  5. Promises/A+ 规范
  6. You Don’t Know JS: Async & Performance

作者: 秦若宸 - 全栈工程师,擅长前端技术与架构设计,个人简历

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/74966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何排查java程序的宕机和oom?如何解决宕机和oom?

排查oom 用jmap生成我们的堆空间的快照Heap Dump&#xff08;堆转储文件&#xff09;&#xff0c;来分析我们的内存占用 用可视化工具&#xff0c;例如java中的jhat分析Heap Dump文件 &#xff0c;它分析完会通过一个浏览器打开一个可视化页面展示分析结果 根据oom的类型来调…

什么是 OLAP 数据库?企业如何选择适合自己的分析工具

引言&#xff1a;为什么企业需要 OLAP 数据库&#xff1f; 你是否曾经经历过这样的场景&#xff1a; 市场部门急需一份用户行为分析报告&#xff0c;数据团队告诉你&#xff1a;“数据太大了&#xff0c;报表要跑 4 个小时”&#xff1b;业务负责人在会议中提出一个临时性分析…

测试:认识Bug

目录 一、软件测试的生命周期 二、bug 一、软件测试的生命周期 软件测试贯穿于软件的生命周期。 需求分析&#xff1a; ⽤⼾⻆度&#xff1a;软件需求是否合理 技术⻆度&#xff1a;技术上是否可⾏&#xff0c;是否还有优化空间 测试⻆度&#xff1a;是否存在业务逻辑错误、…

综合实验2

1、sw1和sw2之间互为备份 [sw1]interface Eth-Trunk 0 &#xff08;创建聚合接口&#xff09; [sw1-Eth-Trunk0]trunkport g0/0/1 &#xff08;将物理接口划入到聚合接口中&#xff09; [sw1-Eth-Trunk0]trunkport g0/0/2 [sw2]interface Eth-Trunk 0 [sw2-Eth-T…

【ArcGIS】ArcGIS10.6彻底卸载和ArcGIS10.2安装全过程

卸载python3后,解决了ArcGIS与python3冲突问题后,软件可以正常打开使用了 但是还是出现了问题 用ArcGIS 进行空间分析时,中间操作没有任何报错和问题,但是就是没有运行结果 在别人的软件上操作一遍可以出现运行结果 关闭确有这个,但真的不是我给它的运行时间不够,反反复复试…

Django之旅:第五节--Mysql数据库操作(一)

Django开发操作数据库更简单&#xff0c;内部提供了ORM框架 一、安装第三方模块 pip install mysqlclient注&#xff1a;最新的django框架需要使用mysqlclient模块&#xff0c;之前pymysql模块与django框架有编码兼容问题。 二、ORM 1、ORM可以帮助我们做两件事&#xff1a;…

docker部署mongodb数据库

1、下载 MongoDB 镜像 使用Docker部署MongoDB 之前&#xff0c;我们需要从 Docker Hub 上下载 MongoDB 镜像。这里我们下载最新版本的 MongoDB 镜像&#xff0c;使用以下命令进行下载&#xff1a; docker pull mongo:latest 下载完成后&#xff0c;我们就拥有了最新版本的 Mon…

Enhanced PEC-YOLO:电力施工场景安全装备检测的轻量化算法解析

目录 一、核心概述 二、核心创新点 1. ​C2F_Faster_EMA模块 2. ​SPPF_CPCA多尺度模块 3. ​BiFPN颈部网络

【人工智能】解锁大模型潜力:Ollama 与 DeepSeek 的分布式推理与集群部署实践

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着大语言模型(LLM)的快速发展,其推理能力在自然语言处理、代码生成等领域展现出巨大潜力。然而,单机部署难以满足高并发、低延迟的需…

RTMP推流服务器nginx在linux上的编译部署

RTMP&#xff08;Real-Time Messaging Protocol&#xff09;推流确实需要服务器支持‌。RTMP推流服务器的主要功能是接收来自推流客户端的数据流&#xff0c;对其进行处理和转发。服务器会根据RTMP协议与客户端建立连接&#xff0c;处理推流数据&#xff08;如转码、录制等&…

PyQt6实例_批量下载pdf工具_主线程停止线程池

目录 前置&#xff1a; 代码&#xff1a; 视频&#xff1a; 前置&#xff1a; 1 本系列将以 “PyQt6实例_批量下载pdf工具”开头&#xff0c;放在 【PyQt6实例】 专栏 2 本系列涉及到的PyQt6知识点&#xff1a; 线程池&#xff1a;QThreadPool,QRunnable&#xff1b; 信号与…

Tomcat生产服务器性能优化

试想以下这个情景&#xff1a;你已经开发好了一个程序&#xff0c;这个程序的排版很不错&#xff0c;而且有着最前沿的功能和其他一些让你这程序增添不少色彩的元素。可惜的是&#xff0c;程序的性能不怎么地。你也十分清楚&#xff0c;若现在把这款产品退出市场&#xff0c;肯…

正则表达式-笔记

文章目录 一、正则表达式二、正则表达式的基本语法字符类普通字符非打印字符特殊字符 量词限定符锚点修饰符&#xff08;标记&#xff09; 三、在 Python 中使用正则表达式简单搜索提取信息替换文本 参考 从验证用户输入&#xff0c;到从大量文本中提取特定信息&#xff0c;再到…

Qwen-0.5b linux部署

参考链接 https://blog.csdn.net/imwaters/article/details/145489543 https://modelscope.cn/models/modelscope/ollama-linux 1. ollama安装 # 安装ModelScope工具包&#xff0c;用于下载和管理AI模型 pip install modelscope# 下载Ollama的Linux版本安装包 # --model 指定…

【深度学习】GAN生成对抗网络:原理、应用与发展

GAN生成对抗网络&#xff1a;原理、应用与发展 文章目录 GAN生成对抗网络&#xff1a;原理、应用与发展1. 引言2. GAN的基本原理2.1 核心思想2.2 数学表达2.3 训练过程 3. GAN的主要变体3.1 DCGAN (Deep Convolutional GAN)3.2 CGAN (Conditional GAN)3.3 CycleGAN3.4 StyleGAN…

【AI速读】CNN图像处理单元的形式化验证方法

近年来,卷积神经网络(CNN)在图像处理和计算机视觉领域取得了巨大成功,如人脸识别、姿态估计等。然而,基于CNN的图像处理单元设计复杂,验证工作面临巨大挑战。传统的仿真验证方法难以覆盖其庞大的配置空间,且耗时费力。本文将介绍一种创新的形式化验证(Formal Verificat…

【新人系列】Golang 入门(八):defer 详解 - 上

✍ 个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4dd; 专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12898955.html &#x1f4e3; 专栏定位&#xff1a;为 0 基础刚入门 Golang 的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们…

鸿蒙开发:了解Canvas绘制

前言 本文基于Api13 系统的组件无法满足我们的需求&#xff0c;这种情况下就不得不自己自定义组件&#xff0c;除了自定义组合组件&#xff0c;拓展组件&#xff0c;还有一种方式&#xff0c;那就是完全的自绘制组件&#xff0c;这种情况&#xff0c;常见的场景有&#xff0c;比…

【Linux笔记】进程间通信——命名管道

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;【Linux笔记】进程间通信——匿名管道||进程池 &#x1f516;流水不争&#xff0c;争的是滔滔不 一、命名管道…

Spring项目中使用EasyExcel实现Excel 多 Sheet 导入导出功能(完整版)

Excel 多 Sheet 导入导出功能完整实现指南 一、环境依赖 1. Maven 依赖 <!-- EasyExcel --> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version> </dependency>…