【JavaScript】异步编程汇总
异步编程解决方案:
- 回调函数
- Promise
- Generator
- await / async
回调函数
回调函数是早期处理异步编程的主要方式,虽然它本身存在很多的缺陷,比如那个时候对于复杂的异步处理常常会出现回调地狱。
但是因为 JavaScript 中当时并没有很好的API来帮助我们以比较优雅的方式编写代码,所以依然应用非常广泛。
function fetchData(url, callback) {setTimeout(() => {callback(url + "/data")}, 2000)
}fetchData('https://www.example.com', (data) => {console.log(data)
})
回调地狱(金字塔式代码):可读性差、维护困难、错误处理复杂。
function fetchData(url, callback) {setTimeout(() => {callback(url + "/data")}, 2000)
}fetchData('https://www.example.com', (data) => {console.log(data)fetchData(data + 'data2', (data2) => {console.log(data2)fetchData(data2 + 'data3', (data3) => {console.log(data3)})})
})
并且从回调函数的设计者和使用者的角度,我们还必须考虑两个问题:
- 从方法设计者的角度:我们需要自己来设计回调函数、回调函数的名称、回调函数的使用等;
- 从方法使用者的角度:对于不同的人、不同的框架设计出来的方案是不同的,那么我们必须耐心去看别人的源码或者文档,以便可以理解它这个函数到底怎么用;
为了解决回调地狱,也为了提供一种统一的异步处理方案,提出了 Promise ,async/ await 等。
Promise
Promise是一个类,可以翻译成承诺、许诺、期约;
当我们需要的时候,给予调用者一个承诺返回(比如我们的fetchData就会返回一个承诺):待会儿我会给你回调数据时,就可以创建一个Promise 的对象;在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor
这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;
当我们调用resolve 回调函数时,会执行Promise 对象的then方法传入的回调函数;
当我们调用reject 回调函数时,会执行Promise对象的catch方法传入的回调函数;
我们可以将它划分成三个状态:
待定(pending): 初始状态,既没有被兑现,也没有被拒绝;当执行executor中的代码时,处于该状态;
已兑现 fulfilled :意味着操作成功完成;执行了resolve 时,处于该状态,Promise已经被兑现;
已拒绝(rejected):意味着操作失败;执行了reject时,处于该状态,Promise已经被拒绝;
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {// 成功: resolveresolve(url + "/data")// 失败// reject(new Error("请求失败"))}, 2000)})
}// resolve => then reject => catch
fetchData('https://www.example.com').then(data => {}).catch(err => {})
之前使用回调函数的示例用 Promise 重构
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {// 成功: resolveresolve(url + "/data")// 失败// reject(new Error("请求失败"))}, 2000)})
}// resolve => then reject => catch
fetchData('https://www.example.com').then(data => {console.log(data)fetchData(data + '/data2').then(data2 => {console.log(data2)})
}).catch(err => {})
但是会发现这样仍然存在回调地狱。所以我们使用:
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {// 成功: resolveresolve(url + "/data")// 失败// reject(new Error("请求失败"))}, 2000)})
}// resolve => then reject => catch
fetchData('https://www.example.com').then(data => {console.log(data)return fetchData(data + '/data2')
}).then(data2 => {console.log(data2)
})
Generator
生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。
平时我们会编写很多的函数,这些函数终止的条件是什么呢?
函数执行完
函数返回,比如return xxx
函数发生异常,比如throw错误
生成器函数也是一个函数,但是和普通的函数有一些区别:
首先,生成器函数需要在function的后面加一个符号:*
其次,生成器函数可以通过yield关键字来控制函数的执行流程:
最后,生成器函数的返回值是一个Generator(生成器):
function* foo() {console.log('111')yieldconsole.log('222')yieldconsole.log('333')
}
const gen = foo()
gen.next() // 111
gen.next() // 222
gen.next() // 333
gen.next() // (无输出)
生成器函数本身也是一个迭代器。
function* foo() {console.log('111')yield '1'console.log('222')yield '2'console.log('333')return ""
}
const gen = foo()
const res1 = gen.next() // 111
console.log(res1) // {value: '1', done: false}
const res2 = gen.next() // 222
console.log(res2) // {value: '2', done: false}
const res3 = gen.next() // 333
console.log(res3) // {value: "", done: true}
const res4 = gen.next()
console.log(res4) // {value: undefined, done: true}
function* foo(value1) {console.log('first:', value1)const value2 = yield '1'console.log('second:', value2)const value3 = yield '2'console.log('third:', value3)return ""
}const gen = foo('arg1')
const res1 = gen.next()
console.log(res1.value)
const res2 = gen.next('arg2')
console.log(res2.value)
const res3 = gen.next('arg3')
console.log(res3.value)
// first: arg1
// 1
// second: arg2
// 2
// third: arg3
之前使用回调函数的示例用 Generator 重构
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url + "/data")}, 2000)})
}function* getData() {const res1 = yield fetchData("https://example.com")console.log(res1)const res2 = yield fetchData(res1 + "/data1")console.log(res2)
}
const gen = getData()
gen.next().value.then(res => {gen.next(res).value.then(res => {gen.next(res)})
})
// https://example.com/data
// https://example.com/data/data1/data
目前我们的写法有两个问题:
第一,我们不能确定到底需要调用几层的Promise关系;
第二,如果还有其他需要这样执行的函数,我们应该如何操作呢?
那么我们能不能使用一种方法让getData自动来执行呢?其实是可以的,这里有两种方法:
方法一:使用co库(https://github.com/tj/co)
方法二:自己编写一个自动执行的函数
这里我们自己编写一个自动执行的函数:
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url + "/data")}, 2000)})
}function* getData() {const res1 = yield fetchData("https://example.com")console.log(res1)const res2 = yield fetchData(res1 + "/data1")console.log(res2)
}/*** 自动执行生成器函数* @param genFn 生成器函数*/
function execGenFn(genFn) {const gen = genFn()// 如果使用 while 循环 由于while是同步任务 而yield是异步任务 所以代码很不好写,很容易造成死循环// 所以使用递归的方式function execFn(res) {const { value, done } = gen.next(res)if (done) {return}value.then(res => {execFn(res)})}execFn()
}
execGenFn(getData)
// https://example.com/data
// https://example.com/data/data1/data
async/await
以上代码还是有些复杂,因此 ES2017 出现了 async/await ,而 ES2015出现的 Promise,因此 Generator 相当于一个过渡的异步编程方案。async/await 就是最新的改进。
之前使用回调函数的示例用 async/await 重构
function fetchData(url, callback) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url + "/data")}, 2000)})
}async function getData() {const res1 = await fetchData("https://example.com")console.log(res1)const res2 = await fetchData(res1 + "/data1")console.log(res2)
}getData()
async 函数的若干种写法
async: 关键字用于声明一个异步函数:
- async是asynchronous.单词的缩写,异步、非同步;
- sync是synchronous.单词的缩写,同步、同时;
异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行。
异步函数有返回值时(new Promise 传入函数参数中函数的返回值同理),和普通函数会有区别:
- 情况一:异步函数也可以有返回值,但是异步函数的返回值会被包裹到 Promise.resolve中;
- 情况二:如果我们的异步函数的返回值是Promise, Promise.resolve 的状态会由 Promise决定;
- 情况三:如果我们的异步函数的返回值是一个对象并且实现了 thenable,那么会由对象的then方法来决定;
如果 async 中出现异常,不会像普通函数那样报错,而是作为 Promise 的 reject 来传递。
// 返回普通值,会被包裹在 Promise.resolve() 中
async function foo() {return "aaa"
}
// 返回一个 Promise 会等待到它的 resolve 或 reject
async function foo2() {return Promise.resolve("bbb")
}// 返回一个 thenable 对象,会被转为 Promise
async function foo3() {return {then(resolve, reject) {resolve("ccc")}}
}foo().then(res => {console.log(res)
})
foo2().then(res => {console.log(res)
})
foo3().then(res => {console.log(res)
})
// 执行顺序: aaa ccc bbb
输出结果都正常,但是顺序可能很多人不理解,这也是一个难点,说明如下。
先来说说 thenable 对象,延迟执行微任务一次。
async function foo() {return "aaa"
}
async function foo2() {// thenable 会延迟一次微任务return {then(resolve, reject) {resolve("ccc")}}
}
foo().then(res => {console.log(res)
}).then(() => {console.log("aaa2")
}).then(() => {console.log("aaa3")
})
foo2().then(res => {console.log(res)
})
// 如果没有 thenable ,顺序为 aaa ccc aaa2 aaa3
// 但真正的输出:
// aaa
// aaa2
// ccc
// aaa3
然后是 Promise.resolve(“bbb”) ,它返回的 then 的微任务延迟执行两次。
async function foo() {return "aaa"
}
async function foo2() {return Promise.resolve("bbb")
}
foo().then(res => {console.log(res)
}).then(() => {console.log("aaa2")
}).then(() => {console.log("aaa3")
}).then(() => {console.log("aaa4")
})
foo2().then(res => {console.log(res)
})
// 如果没有 thenable ,顺序为 aaa ccc aaa2 aaa3
// 但真正的输出:
// aaa
// aaa2
// aaa3
// bbb
// aaa4
await 的使用
async 函数另外一个特殊之处就是可以在它内部使用await:关键字,而普通函数中是不可以的。
await关键字有什么特点呢?
通常使用await 是后面会跟上一个表达式,这个表达式通常会返回一个Promise。那么awaits会等到Promise的状态变成fulfilled状态,之后继续执行异步函数。
await不同值的处理:
- 如果await后面是一个普通的值,那么会直接返回这个值;
- 如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值;
- 如果await 后面的表达式,返回的Promise是reject的状态,那么会将这个reject结果直接作为函数的Promise的reject值;
async function foo() {const res = await new Promise(resolve =>{setTimeout(() => {resolve('111')}, 2000)})// 以下会被放在微任务中执行console.log(res)
}
foo()
async function foo() {const res = await new Promise((resolve, reject) => {setTimeout(() => {reject(new Error('foo error'))}, 2000)})console.log(res)
}
foo().catch(err => {console.log(err)
})
异步编程面试题
回调函数在异步编程中的作用和缺点
- 回调函数是前端开发中非常重要的一种编程方式
因为 JavaScript 是支持函数式编程的,所以函数可以作为第一公民传递给另外一个函数。
那么另外一个函数在合适的时机可以反过来调用这个函数,被调用的这个函数我们就称之为是回调函数。
- 在早期的 JavaScript 异步编程中,回调函数的应用是非常广泛的:
比如说网络请求、用户交互的事件回调、Timer定时器等;
我们都不确定事件在什么时候完成,所以我们需要通过回调函数来监听事件的完成,并且执行对应的操作。
这样做一方面不会引起我们主线程的阻塞,另一方面可以在合适的时机去执行某些特定函数的代码。
- 但是回调函数也是有缺点的,因为我们经常需要在一个异步回调中,去执行其他的异步操作,而其他的异步操作往往又会有对应的回调函数,这样就会引起回掉地狱(Callback Hell)。
比如我们在早期的开发中,一个网络请求获取到数据后,我们会根据这个请求立马就发送另外一个请求,并且获取到数据后可能再次回发送另外一个请求。
也就是多个异步操作需要按照某种特定的顺序执行时,常常会产生回调地址。
这种依赖关系可能会引起回调函数的嵌套,造成我们的代码可读性、可维护性变差。
另外回调函数的错误处理机制相对复杂,处理起来也非常麻烦。
解决回调地狱
在早期没有 Promise 的情况下,解决回调地狱确实是比较棘手的一个问题。但是如果项目不引入解决方案,往往会让代码后期非常复杂,难以维护,所以我在架构项目时,对多异步编程的代码就会制定统一的规范:
- 方案一:函数单独封装
当你遇到复杂的嵌套回调时,可以将每个异步的步骤单独抽取成函数,来避免回调地狱。
这种方式是将回调函数抽取到外部,单独去调用,这样代码结构会更加扁平化,便于理解和维护。
- 方案二:使用Async.js库
Async.js是一个非常流行的控制流库,这个库提供了许多的高阶函数来简化异步的操作。
比如waterfall,可以按照顺序执行一系列的异步任务,并且可以将结果传递给下一个任务。
当然,如果不想引入这种第三方库,我们也可以自己来封装实现。
- 也有其他的解决方案,比如nodejs中基于事件驱动,当有异步的结果时会发出一个事件,在其他地方来监听事件进行后续的操作,避免回调的嵌套。
当然,在Promise、Generator、await、async出现之后,对于异步的处理,变得非常的简单和优雅了。
Promise 是什么
Promise是一种用于处理异步操作的 JavaScript 类,可以通过这个类创建出Promise 的对象。
当我们创建一个Promise对象返回给其他人时,相当于给到其他人一个"承诺”,这个承诺会在之后的某个时间点“兑现”或者“拒绝”。
因为对于一个Promise来说有三种状态:Pending(等待)、Fulfilled(兑现或者完成)、Rejected(拒绝或者失败)。
Promise允许我们通过.then() 方法处理成功的结果,通过.catch() 方法处理失败的结果。
这种链式调用极大地提高了异步代码的可读性和维护性。
- 所以Promisei引入的核心就是提供一种更加优雅的方式来处理异步操作,避免传统的回调函数复杂性。
- 在Promisei引入之前,JavaScript 主要依赖回调函数来处理异步操作。
这种方式在处理简单异步任务时还算有效,但随着异步操作的复杂性增加,特别是在多个异步任务需要依次或并行执行时,回调函数会导致所谓的“回调地狱”问题。
回调地狱使得代码变得难以阅读、调试和维护。
- 虽然之前也有解决方案,但是存在两个问题:
解决方案是基于现有的回调函数缺点提出的,其实并不优雅。
不同的项目、企业可能采用不同的解决方案,没有统一的标准。
生成器
- 生成器(Generator)是 JavaScript 中一种特殊的函数类型,和普通的函数相比,它在定义时是通过
function*
语法定义。
普通的函数只有等到执行完毕或者return 或者抛出异常时才会终止。
而生成器函数可以控制它的“暂停”和“恢复”执行。
生成器函数每次调用这个迭代器的next() 方法时,生成器函数会从上次暂停的地方继续执行,直到遇到yield表达式或者函数结束。
- 生成器函数的核心特点是它可以暂停执行,并通过 yield 关键字将控制权交还给调用者,同时还能保留当前的执行上下文。
- 在异步编程中,生成器可以被用来简化复杂的异步逻辑,在没有引入await、async之前,我们可以借助于Promise+Generator 实现await、async的功能(因为await、async是到ES8才成为标准的)
可以通过生成器函数来代替async的功能
可以通过yield来代替await的功能
- 只是代码的执行需要借助于co库或者我们自己编写代码来让生成器函数可以自动执行。
async/await 是什么
- async和await是ES2017(ES8) 引入的两个关键字,它们目的是让我们的异步代码处理起来更加的优雅,可以把异步代码像同步代码那样去编写,这样可以提供我们代码的可读性、可维护性。
- async 用于声明一个异步函数,它本质上是一个返回Promise的函数。
无论函数内部是否手动的返回一个Promise对象,都会将返回值包装到一个Promise来处理;
如果我们的异步函数的返回值是Promise, Promise.resolve的状态会由Promise决定;
如果我们的异步函数的返回值是一个对象并且实现了thenable, 那么会由对象的then方法来决定;
如果函数内部发生了异常,那么函数就会执行Promise的reject操作。
- await只能在async 函数内部使用,它用于等待一个Promise 的结果。
通常使用await: 是后面会跟上一个表达式,这个表达式会返回一个Promise;
那么await 会等到Promise的状态变成fulfilled 状态,之后继续执行异步函数;
- async/await. 与Promisel的优势和不同:
- 编写方便:在处理多个异步操作时,我们可以通过await关键字轻松实现同步代码的编写方式,编写起来更加方便。
- 代码可读性和可维护性:使用async/awaiti语法,我们可以像编写同步代码那样来编写异步代码,避免了Promise链式调用的嵌套。
- 错误处理:在Promiser中,错误处理通常通过.catch()方法进行,而在async/await中,我们可以直接使用try.catch 来捕获和处理异常。
相关文章:
【JavaScript】异步编程汇总
异步编程解决方案: 回调函数PromiseGeneratorawait / async 回调函数 回调函数是早期处理异步编程的主要方式,虽然它本身存在很多的缺陷,比如那个时候对于复杂的异步处理常常会出现回调地狱。 但是因为 JavaScript 中当时并没有很好的API来帮…...
【AI系列】从零开始学习大模型GPT (2)- Build a Large Language Model (From Scratch)
前序文章 【AI系列】从零开始学习大模型GPT (1)- Build a Large Language Model (From Scratch) Build a Large Language Model 背景第1章:理解大型语言模型第2章:处理文本数据第3章:编码Attention机制什么是Attention机制?Attention机制的基本原理数学表示应用总结为什么要…...
动态规划——路径问题②
文章目录 931. 下降路径最小和算法原理代码实现 64. 最小路径和算法原理代码实现 174. 地下城游戏算法原理代码实现 931. 下降路径最小和 题目链接:931. 下降路径最小和 算法原理 状态表示: 经验题目要求:dp[i][j]表示到达[i,j]位置时&…...
【每日关注】科技圈重要动态
时代新动态 2025 年 2 月 12 日科技圈重要动态总结全球 AI 治理新进展巴黎 AI 宣言签署,美英缺席 科技巨头合作与竞争苹果联姻阿里开发中国版AI功能DeepSeek生态持续扩展OpenAI拒绝马斯克收购,矛盾公开化 汽车行业动态小米汽车销量跃居新势力第二比亚迪智…...
Postgresql的三种备份方式_postgresql备份
这种方式可以在数据库正在使用的时候进行完整一致的备份,并不阻塞其它用户对数据库的访问。它会产生一个脚本文件,里面包含备份开始时,已创建的各种数据库对象的SQL语句和每个表中的数据。可以使用数据库提供的工具pg_dumpall和pg_dump来进行…...
Linux 配置 MySQL 定时自动备份到另一台服务器
Linux 配置 MySQL 定时自动备份到另一台服务器这里写自定义目录标题 前言1、配置服务器通信1.1:配置过程 2、编写自动备份sh脚本文件3:设置定时自动执行 前言 此方案可使一台服务器上的 MySQL 中的所有数据库每天 0 点自动转储为 .sql 文件,…...
CCF-GESP 等级考试 2024年6月认证C++二级真题解析
2024年6月真题 一、单选题(每题2分,共30分) 正确答案:C 考察知识点:计算机基础与编程环境 解析:CCF 组织的 GESP 认证考试第 1 级可选择的认证语言有 Scratch、Python、C ,共 3 种。答案为C。 …...
vm虚拟机的一些操作命令
PowerShell命令 // 获取虚拟机列表: get-vm // 创建虚拟机: new-vm -Name "BrioDev75" -MemoryStartupBytes 16GB -Path "D:\Hyper-V" // 删除虚拟机: remove-vm -Name "BrioDev75" -Force (-Force参数是…...
sql难点
一、 假设你有一个查询,需要根据 id 是否为 null 来动态生成 SQL 条件: xml复制 <select id"getResources" resultType"Resource">SELECT * FROM resources<where><if test"id ! null">and id <!…...
【多模态大模型】系列1:Transformer Encoder——ViLT、ALBEF、VLMO
目录 1 ViLT2 ALBEF3 VLMO 1 ViLT ViLT: Vision-and-Language Transformer Without Convolution or Region Supervision 图文多模态任务,关键是提取视觉特征和文本特征,然后对齐。在之前的多模态研究工作中,视觉侧通常需要一个目标检测器来…...
2.4 测试数据与初始化
测试数据与初始化 在 Spring Test 中,合理管理测试数据的初始化和清理是保证测试可靠性的关键。本章将介绍多种数据准备方式,涵盖 SQL 脚本执行、编程式初始化 和 动态数据生成,并提供最佳实践示例。 1. 使用 Sql 执行 SQL 脚本 作用 在测…...
DataBase【MySQL基础夯实使用说明(中)】
MySQL数据库 🏆当领导问你忙不忙,您怎么回复? 🔔要让领导知道你很忙,但是你的事情紧急,我可以优先处理! 文章目录 MySQL数据库前言一、SQL(Structured Query Language)1…...
Unity3D Shader 简析:变体与缓存详解
引言 在 Unity3D 中,Shader 是渲染管线的核心部分,负责控制物体的外观和材质表现。Shader 的变体(Variants)和缓存机制是优化渲染性能的关键。本文将深入探讨 Unity3D 中 Shader 变体的概念、缓存机制以及如何通过代码实现和管理…...
vuex基础介绍
/store/index.js import Vue from vue import Vuex from vuexVue.use(Vuex)/*** 创建并导出一个 Vuex 仓库实例* 仓库是一个存储应用所有状态的容器,并且提供了修改和获取状态的方法*/ export default new Vuex.Store({// state 是一个对象,用于存储应…...
OpenWRT中常说的LuCI是什么——LuCI介绍(一)
我相信每个玩openwrt的小伙伴都或多或少看到过luci这个东西,但luci到底是什么东西,可能还不够清楚,今天就趁机来介绍下,openwrt中的luci,到底是个什么东西。 什么是LuCI? 首先,LuCI是OpenWRT中…...
singleTaskAndroid的Activity启动模式知识点总结
一. 前提知识 1.1. 任务栈知识 二. Activity启动模式的学习 2.1 standard 2.2 singleTop 2.3.singleTask 2.4.singleInstance 引言: Activity作为四大组件之一,也可以说Activity是其中最重要的一个组件,其负责调节APP的视图ÿ…...
DeepSeek-V3 技术报告
1.摘要 为了减少开源模型与闭源模型的能力差距,我们提出了DeepSeek-V3,一个大的混合专家模型(Mixture-of-Experts (MoE) ),有6710亿参数,每个token会激活370亿参数。 DeepSeek-V3采用多头隐注意力…...
Vue 3 30天精进之旅:Day 22 - 构建和部署
欢迎回来!在我们的Vue 3学习旅程的第22天,我们将探讨应用的构建和部署。在完成了我们的应用开发后,下一步就是如何将其部署到服务器,使得用户可以访问。 1. 构建Vue应用 构建Vue应用是将我们在本地开发的代码打包成生产环境可用…...
Ansible中Playbook的逻辑控制语句-when
playbook的逻辑控制语句 when 条件判断语句,类似if loop 循环语句,类似loop block 将几个任务组成一个代码块,便于针对一组操作的异常进行处理 when的基本用法 when的运算符操作 when关键字可以配合各种运算符进行操作,如下&…...
制造业物联网的十大用例
预计到 2026 年,物联网制造市场价值将达到 4000 亿美元。实时收集和分析来自联网物联网设备与传感器的数据,这一能力为制造商提供了对生产流程前所未有的深入洞察。物联网(IoT)有潜力彻底改变制造业,使工厂能够更高效地…...
InfiniBand与IP over InfiniBand(IPOIB):实现高性能网络通信的底层机制
在现代高性能计算(HPC)和数据中心环境中,网络通信的效率和性能至关重要。InfiniBand(IB)作为一种高性能的串行计算机总线架构,以其低延迟、高带宽和高可靠性而广泛应用于集群计算和数据中心。IP over InfiniBand(IPOIB)则是在InfiniBand网络上实现IP协议的一种方式,它…...
【通俗易懂说模型】一篇弄懂几个经典CNN图像模型(AlexNet、VGGNet、ResNet)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …...
机器学习 | scikit-learn中分块拟合vs一次性拟合所有数据
Scikit-learn是一个广泛使用的机器学习Python库,提供了一系列分类、回归、聚类等算法。机器学习的关键挑战之一是处理无法一次性放入内存的大型数据集。本文探讨了使用scikit-learn将数据分块拟合与一次性拟合的策略,讨论了每种方法的优点和局限性。 大…...
两个同一对象targetList和 sourceList 去重
我现在需要解决的问题是从一个Java的源列表`sourceList`中移除所有在目标列表`targetList`中存在的数据,并且还要去除`targetList`中的重复数据。让我先理清楚这两个问题的思路。 首先,如何快速从`sourceList`中移除含有`targetList`的数据。这里的“含有”应该是指两个列表中…...
小游戏源码开发之可跨app软件对接是如何设计和开发的
专业小游戏开发的团队往往会面临跨领域和不同平台客户需要追加同一款游戏的需求,所以就要设计和开发一款可任意对接不同 App 软件的小游戏,那么针对这类需求小游戏开发团队早已有了成熟的解决方案,针对设计和开发可跨平台游戏对接大概流程简单…...
掌握正则表达式_模式匹配的艺术
当然,以下是《掌握正则表达式:模式匹配的艺术》文章内容,使用 Java 正则表达式,并包含丰富的代码示例: 1. 引言 1.1 正则表达式的定义与历史 正则表达式(Regular Expression,简称 regex 或 regexp)是一种用于描述文本模式的强大工具。它最初由数学家 Stephen Kleene…...
FacePoke详细使用指南:如何利用开源AI工具优化照片人物表情
文章目录 前言1. 本地使用FacePoke1.1 整合包方式安装1.2 Docker方式部署 2. FacePoke功能演示3. 公网使用FacePoke3.1 创建远程连接公网地址 4. 固定远程访问公网地址 前言 在数字创意的世界里,一款名为FacePoke的工具正以其风趣而强大的功能吸引着无数创作者的目…...
本地部署【LLM-deepseek】大模型 ollama+deepseek/conda(python)+openwebui/docker+openwebui
通过ollama本地部署deepseek 总共两步 1.模型部署 2.[web页面] 参考官网 ollama:模型部署 https://ollama.com/ open-webui:web页面 https://github.com/open-webui/open-webui 设备参考 Mac M 芯片 windows未知 蒸馏模型版本:deepseek-r1:14b 运行情况macminim2 24256 本地…...
分发饼干(力扣455)
从这道题开始我们就进入贪心算法的学习了。这个算法没有固定的套路,甚至题目之间的联系也很少,基本上每一道题都要当新题来写。我们能做的只有见多识广,这样才有机会在考试中根据以往经验解决贪心的题目。贪心的本质上就是找到局部最优解&…...
信息收集-主机服务器系统识别IP资产反查技术端口扫描协议探针角色定性
知识点: 1、信息收集-服务器系统-操作系统&IP资产 2、信息收集-服务器系统-端口扫描&服务定性 一、演示案例-应用服务器-操作系统&IP资产 操作系统 1、Web大小写(windows不区分大小写,linux区分大小写) 2、端口服务特征(22就是linux上的服…...
建筑兔零基础自学python记录18|实战人脸识别项目——视频检测07
本次要学视频检测,我们先回顾一下图片的人脸检测建筑兔零基础自学python记录16|实战人脸识别项目——人脸检测05-CSDN博客 我们先把上文中代码复制出来,保留红框的部分。 然后我们来看一下源代码: import cv2 as cvdef face_detect_demo(…...
vue-点击生成动态值,动态渲染回显输入框
1.前言 动态点击生成数值,回显输入框,并绑定。 2.实现 <template><div style"display:flex;align-items: center;flex-direction:row"><a-input:key"inputKey"v-model"uploadData[peo.field]"placehold…...
Idea 插件 Quickly-Code-Toolkit
使用说明 (一)全局设置 Paging Wrapper Setting(分页设置) 功能:主要用于在方法写入时,为返回参数提供分页包装类。设置方式:需准确填写分页包装类的全限定名,例如:com…...
fun-transformer学习笔记-Task1——Transformer、Seq2Seq、Encoder-Decoder、Attention之间的关系
Transformer、Seq2Seq、Encoder-Decoder、Attention由这四者之间的关系可以从模型架构的发展脉络来理解: Seq2Seq 与 Encoder–Decoder 模型 “Seq2Seq”(sequence‐to‐sequence)是一类用于将一个变长序列映射为另一个变长序列的任务&#x…...
使用瑞芯微RK3588的NPU进行模型转换和推理
使用边缘设备进行算法落地时,通常要考虑模型推理速度,NVIDA系列平台可以使用TensorRT和CUDA加速,瑞芯微RK3588的板子上都是Arm的手机GPU,虽然没有类似CUDA的加速计算方式,但是提供了NPU进行加速推理,本文说…...
mysql读写分离与proxysql的结合
上一篇文章介绍了mysql如何设置成主从复制模式,而主从复制的目的,是为了读写分离。 读写分离,拿spring boot项目来说,可以有2种方式: 1)设置2个数据源,读和写分开使用 2)使用中间件…...
Vue笔记(九)
一、文章分类架子--PageContainer 学习PageContainer组件的封装,这一组件用于搭建页面基础结构,为后续内容展示提供统一布局。它可能包含通用的页面样式、导航栏、侧边栏等基础元素的结构搭建。 在Vue组件中, <template> 标签内定义基础…...
YOLO11框架使用
YOLO11 1. Frame Understanding2. What can YOLO11 do?3.如何训练自己数据集?3.1 配置环境3.2 制作自己数据集3.3 配置文件3.3.1 数据集配置文件3.3.2 网络模块配置文件4.修改训练参数配置文件5. 训练脚本编写6.结果展示1. Frame Understanding 2. What can YOLO11 do? Ult…...
RK3588视觉控制器与AI 算法:开启工业视觉检测新境界
在实际应用中,工业相机拍摄产品的图像,RK3588 迅速接收并进行预处理。AI 算法随即对图像进行深入分析,提取特征并与预设的标准进行对比,从而准确判断是否存在缺陷。 例如,在电子元件生产线上,RK3588 和 AI…...
C语言基础入门:2.5基础输入输出
【C语言基础】输入输出完全指南:从printf到缓冲区安全 文章目录 【C语言基础】输入输出完全指南:从printf到缓冲区安全一、格式化输出艺术:printf函数详解二、scanf输入安全与缓冲区处理三、字符级交互:getchar与putchar实战程序员…...
压缩stl文件大小
1、MeshLab下载界面,从MeshLab下载适合自己系统的最新版本。 2、打开 MeshLab软件,将stl文件拖入其中。 3、 4、Percentage reduction参数即为缩放比例,根据自身想要将文件压缩到多大来。 然后点击apply 5、CtrlE弹出窗口保存文件后&…...
二、交换机的vlan子设备接入
一、交换机的vlan设置-CSDN博客 二、交换机的vlan子设备接入-CSDN博客 接上篇的文章,本文接入了子设备 网络结构如下: 用路由器A和POE交换机B代替第一篇中的笔记本电脑,路由器A和交换机B都关闭DHCP服务,并分别接入一个IPC&#…...
KEPServerEX 的接口类型与连接方式的详细说明
目录 一、KEPServerEX 核心架构 二、KEPServerEX 支持的接口类型 三、KEPServerEX 支持的连接类型 1. 通用工业协议 2. 品牌专属协议 3. 行业专用协议 4. 数据库与文件接口 四、配置示例 1. 接口配置(以OPC UA为例) 2. 连接配置(以…...
Stack(栈)
定义:在Java编程语言中,栈(Stack)是一种非常重要的数据结构,具有后进先出的特性,即最后入栈的元素最先出栈。栈通常用于存储临时性的数据,如方法调用过程中的局部遍历、操作数栈等。 图像理解: 我们在这里要…...
【Vue3 Computed 与 Watch 维护对比】
让我们从开发体验和维护性的角度深入对比 computed 和 watch,通过具体场景分析它们的差异: 一、维护成本对比 1. 依赖管理差异 // 原始代码 const productFilter computed(() > {return products.value.filter((p) > p.price > minPrice.val…...
在node.js环境中使用web服务器http-server运行html静态文件
http-server http-server是一个超轻量级web服务器,它可以将任何一个文件夹当作服务器的目录供自己使用。 当我们想要在服务器运行一些代码,但是又不会配置服务器的时候,就可以使用http-server就可以搞定了。 使用方法 因为http-server需要…...
详解电子邮箱工作原理|SMTP、POP3、IMAP、SPF、MIME
写在前面 电子邮件(Email)是一种通过互联网进行异步通信的技术,工作原理涉及多个协议、服务器和客户端协同工作。 接下来我们来介绍一下电子邮箱的工作原理 1. 电子邮件的核心组成部分 邮件客户端:用户直接交互的软件…...
算法学习笔记之并查集
简介 问题描述:将编号为1-N的N个对象划分为不相交集合,在每个集合中,选择其中的某个元素代表所在集合。 常见两种操作: 1.合并两个集合 2.查找某元素属于哪个集合 实现方法1 用编号最小的元素标记所在集合; 定义…...
【开源项目】ShowDoc适合IT团队的在线API文档、技术文档工具
1. 介绍 通过showdoc,可以方便地使用markdown语法来书写出美观的API文档、数据字典文档、技术文档、在线excel文档等等。还可以利用showdoc的自动化能力,从程序注释中自动生成API文档,或者从搭配的RunApi客户端(类似postman的api…...
Tomcat添加到Windows系统服务中,服务名称带空格
要将Tomcat添加到Windows系统服务中,可以通过Tomcat安装目录中“\bin\service.bat”来完成,如果目录中没有service.bat,则需要使用其它方法。 打到CMD命令行窗口,通过cd命令跳转到Tomcat安装目录的“\bin\”目录,然后执…...