异步编程(Promise详解)
目录
异步编程
回调函数
回调地狱
Promise
基本概念
Promise的特点
1.Promise是一种构造函数
2.Promise接收函数创建实例
3.Promise对象有三种状态
4.Promise状态转变不可逆
5.Promise 实例创建即执行
6.Promise可注册处理函数
7.Promise支持链式调用
Promise的静态方法
1.resolve()方法
2.reject()方法
3.all()方法
4.race()方法
5.allSettled() 方法
Promise的实例方法
1.then() 方法
2.catch() 方法
3.finally() 方法
async/await
基本概念
基本用法
async
await
使用示例
async/await 的优势
异步编程
JavaScript 在设计之初就是单线程的,这意味着它在同一时间只能执行一个任务,然而,浏览器和 Node.js 环境都提供了多种机制来允许 JavaScript 代码在不阻塞主线程的情况下执行异步操作。
此处仅以浏览器环境下举例( 参考浏览器渲染基本原理 )
浏览器有三大进程 —— 网络进程,浏览器进程和渲染进程。每个窗口开启一个渲染进程。每个渲染进程仅开启一个渲染主线程,主线程负责执行代码(HTML,CSS,JS),渲染页面。
所以在浏览器中,JS是运行在承担着诸多工作的渲染主线程上的。如果使用同步的方式(等待任务结束再执行下一个任务),就有可能会造成阻塞,浪费主线程的宝贵时间;还可能导致页面无法及时更新,给用户造成“卡死”现象。
所以采用异步执行来避免:当发生耗时任务时,渲染主线程会将任务交给其它渲染子线程取处理,自身则立即结束任务的执行,转而执行后续代码。当其他线程完成处理后,会将事先传递的回调函数包装成任务,加到消息队列末尾排队,等待渲染主线程通过事件循环机制调度执行。
在这种异步模式下,浏览器永不阻塞,从而最限度的保证了单线程的流畅运行。
举例:
setTimeout(function () {console.log('异步任务')
}, 0)
console.log('同步任务')
// 输出顺序 同步任务 ,异步任务
使用异步方式执行任务,在不阻塞主线程的同时还能极大的缩短程序执行所需的时间
该图摘自菜鸟教程中的
异步编程
小节
回调函数
在JavaScript中,回调函数是一段可执行的代码段(function),它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段代码(简单来说就是函数作为参数传递到另外一个函数中,这个作为参数的函数就是回调函数)。
回调函数是 JavaScript 异步编程中最早也是最基本的模式。当一个异步操作完成时,它会调用事先定义好的回调函数来处理异步操作完成后的结果或响应。
回调函数在异步编程中的作用:将异步操作的处理逻辑封装在回调函数中,然后在异步操作完成时执行这些逻辑。这有助于将异步代码与同步代码分离,使得程序的结构更加清晰。
const success = (data) => {console.log('请求成功,开始处理' + data)//....其他操作
}
const fail = (err) => {console.log('请求失败,开始处理错误' + err)//....其他操作
}
//回调函数callback1,请求失败时的操作
//回调函数callback2,请求成功时的操作
function foo(signal, callback1, callback2) {//模拟异步请求setTimeout(() => {if (signal === 'ok') {callback1('data')} else callback2('err')}, 1000)
}
foo('ok', success, fail)
在上面的例子中,等待1s后(模拟耗时任务),根据任务结果(此处我用foo()的第一个参数‘ok’代替),传递任务结果并调用相应的回调函数。
回调地狱
最简单的网络请求大概是这样
请求1(function callback(请求1的结果) {处理请求1的结果
})
很简单
但是随着需求的变化,当我们需要根据第一次请求的结果进行第二次请求时
请求1(function callback(请求结果1) {//根据请求1的结果,进行请求2请求2(function callback(请求结果2) {处理请求结果2})
})
也不复杂
直至,需求不断变化,最终出现了类似下面的情况
请求1(function callback(请求结果1) {//根据请求1的结果,进行请求2请求2(function callback(请求结果2) {//根据请求2的结果,进行请求3请求3(function callback(请求结果3) {//根据请求3的结果,进行请求4请求4(function callback(请求结果4) {//根据请求4的结果,进行请求5请求5(function callback(请求结果5) {// ...})})})})
})
这下懵圈了,在异步请求和回调函数的不断嵌套下,臭名昭著的 回调地狱 诞生了。
试想一下,在回调函数内部可能会存在大量的处理逻辑,并且每一次的请求结果会成为下一请求的依赖,请求又会存在有失败和成功两种情况.....如此一来,代码将显得十分臃肿复杂,后期为维护将变得十分困难。
回调地狱带来的负面作用:
- 代码臃肿
- 可读性差
- 耦合度过高,可维护性差
- 代码复用性差
- 容易滋生 bug
- 只能在回调里处理异常
Promise
基本概念
为了优雅的解决回调地狱的问题,在ES6中,一种新的异步编程的一种解决方案Promise诞生了。
在JS中,Promise是一个代表了异步操作最终完成或失败,及其结果值的对象。它允许开发人员为异步操作的成功和失败情况注册处理程序,极大地简化了异步编程的复杂性。
Promise的特点
1.Promise是一种构造函数
通过new关键字创建实例对象,构造函数自身有all,race,reject,resolve等静态方法,其原型对象上有then,catch,finally等方法。
let promise = new Promise(() => {})
console.log(typeof Promise)//function
console.log(typeof promise)//object//查看Promise函数对象
console.dir(Promise)
2.Promise接收函数创建实例
创建一个新的Promise实例时,必须传递一个函数作为参数给Promise
的构造函数,它定义了异步操作的逻辑。这个函数被称为执行器(executor)函数,它本身接受两个函数作为参数:resolve
和reject
。这两个参数也是函数,由JavaScript引擎提供,用于改变Promise的状态。
let promise = new Promise((resolve, reject) => {})
3.Promise对象有三种状态
分别为pending(进行中),fulfilled(已成功)和rejected(已失败),其通过执行器(executor)函数接收的resolve和reject来改变。
1). new Promise()
let promise = new Promise((resolve, reject) => {})
console.dir(promise)
新创建的promise实例,其状态为pending(进行中),结果为undefined
2). resolve(value)
let promise = new Promise((resolve, reject) => {resolve('完成结果值')
})
console.dir(promise)
resolve()接收异步任务执行结果的值作为参数,并将promise实例的状态转变为fulfilled(已成功),结果为 resolve()接收的值
3).rejected(reason)
let promise = new Promise((resolve, reject) => {reject('完成失败原因')
})
console.dir(promise)
rejected()接收异步任务执行失败的原因作为参数,并将promise实例的状态转变为rejected(已失败),结果为 rejected()接收的失败原因
4.Promise状态转变不可逆
Promise 状态的转变是不可逆且只能发生一次,且只能由异步操作结果决定。任何其他操作都不能改变这个状态
5.Promise 实例创建即执行
let promise = new Promise((resolve, reject) => {reject('获取数据失败')
})
创造 promise
实例后,它会立即执行的特点,所以该段代码运行后会立即抛出一个错误
但如果将其放入函数的私有作用域内,由于函数的特性,promise仅在函数被调用时,才会执行
6.Promise可注册处理函数
可通过.then()和.catch()方法为promise注册处理函数,在promise状态改变时调用(then和catch的具体用法见下方Promise的实例方法)
7.Promise支持链式调用
建议先阅读下方Promise的实例方法。Promise链式调用的核心时then方法,由于then方法返回一个新的 Promise实例对象(该对象也就可以调用promise的实例方法),这使得我们可以继续链式调用其他then()方法。如此一来便可以很容易地处理异步操作的序列。
注意:then()的链式调用中,下一个依赖于上一个返回结果
举例:
function fetchData(url) {return new Promise((resolve, reject) => {// 假设这是一个异步请求数据的函数setTimeout(() => {if (url) {resolve(`数据来自 ${url}`)} else {reject('URL 不能为空')}}, 1000)})
}
// 链式调用
fetchData('https://example.com').then((data) => {console.log(data) // 输出:数据来自 https://example.comreturn fetchData('https://another.com') // 返回另一个 Promise}).then((anotherData) => {console.log(anotherData) // 输出:数据来自 https://another.com}).catch((error) => {console.error('捕获到错误:', error) // 如果有 Promise 被拒绝,则执行这里}).finally(() => {console.log('所有操作完成,无论成功还是失败') // 无论成功还是失败都会执行})
Promise的静态方法
Promise 提供了几个静态方法,这些方法不是用于创建新的 Promise 实例的,而是用于处理 Promise 对象的集合或进行某些特定的操作(只能由构造函数调用)。
1.resolve()方法
静态方法 Promise.resolve(value) 将异步执行的结果value作为参数,返回一个以给定值解析后的已完成状态的 Promise 对象。
Promise.resolve('成功了').then((value) => {console.log(value) // 输出: 成功了})// 如果传入的是 Promise 对象,则直接返回该 Promise 对象let promise = new Promise((resolve) =>resolve('直接返回的 Promise'))Promise.resolve(promise).then((value) => {console.log(value) // 输出: 直接返回的 Promise})
2.reject()方法
静态方法 Promise.reject(reason) 返回一个以特定原因(reason)拒绝状态的 Promise 对象。
Promise.reject('出错了').catch((error) => {console.log(error) // 输出: 出错了
})
3.all()方法
静态方法 Promise.all( iterator ) 用于处理一个 Promise 对象的数组(或可迭代对象),并返回一个新的 Promise 实例。这个新的 Promise 实例会在所有给定的 Promise 都成功完成时才会成功完成,其结果是一个数组,包含了所有给定 Promise 的结果(按相同的顺序)。
function delay(time, value) {return new Promise((resolve) =>setTimeout(() => resolve(value), time))
}
Promise.race([delay(1000, '1s'),delay(2000, '2s'),delay(3000, '3s')
]).then((results) => {console.log(results) // 输出: ['1s', '2s', '3s']
})
4.race()方法
静态方法 Promise.race( iterator ) 同样接收一个 Promise 对象的数组(或可迭代对象),但它返回的新 Promise 实例会在给定的 Promise 数组中任何一个 Promise 改变状态(无论是成功还是失败)时,立即以那个 Promise 的结果作为自己的结果来改变状态。
function delay(time, value) {return new Promise((resolve) =>setTimeout(() => resolve(value), time))
}
Promise.race([delay(1000, '1s'),delay(2000, '2s'),delay(3000, '3s')
]).then((results) => {console.log(results) // 输出: 1s,因为第一个 delay(1000) 最快完成
})
5.allSettled() 方法
静态方法 Promise.allSettled(iterable)(ES2020 新增) 返回一个在所有给定的 Promise 都已经 settled(完成,无论结果如何)后完成的 Promise 实例,结果是一个数组,数组中的每个元素都是一个对象,表示对应的 Promise 的结果。
Promise.allSettled([Promise.resolve(3),Promise.reject(-1),Promise.resolve(5),Promise.reject(4)
]).then((results) => {console.log(results)
})
/* 输出:
[ { status: 'fulfilled', value: 3 }, { status: 'rejected', reason: -1 }, { status: 'fulfilled', value: 5 }, { status: 'rejected', reason: 4 },
]
*/
Promise的实例方法
Promise 的实例方法主要包括 .then(), .catch(), 和 .finally()。这些方法允许你以链式调用的方式处理 Promise 的结果或错误。
1.then() 方法
1).then(onFulfilled , onRejected)
- onFulfilled :指定resolve时调用的函数,它接收 Promise 的值作为参数(一般由resolve传递)
- onRejected( 可选 ):指定reject时调用的函数,它接收 Promise 的拒绝原因作为参数(一般由reject传递)
2).then()
方法主要用于处理 Promise 成功的情况,但也允许提供可选第二个参数 onRejected
函数来处理其失败的情况
3).then() 返回一个新的 Promise 实例对象
let promise = new Promise((resolve, reject) => {setTimeout(() => reject('出错了'), 1000)
})
promise.then((value) => console.log(value), // 不会被调用,因为 Promise 被拒绝了(reason) => console.log(reason) // 会被调用,并输出: 出错了
)
2.catch() 方法
1).catch(onRejected)方法是 .then(null, onRejected) 的语法糖
- onRejected:指定reject时调用的函数,它接收 Promise 的拒绝原因作为参数(一般reject传递)
2)catch() 主要用于处理 Promise 拒绝(rejected)的情况
3).catch() 也返回一个新的 Promise 实例对象
let promise = new Promise((resolve, reject) => {setTimeout(() => reject('出错了'), 1000)
})
promise.catch((error) => {console.log(error) // 输出: 出错了// 可以选择在这里解决这个 Promise,返回一个值或者另一个 Promise// return '错误已处理';
})
4).不过它还有另外一个作用:在执行 resolve
的回调(也就是上面 then
中的第一个参
数)时,如果抛出异常了(代码出错了),那么并不会报错卡死 js,而是会进到这个
catch
方法中。
let promise = new Promise((resolve, reject) => {setTimeout(() => reject('失败'), 1000)
}).then((value) => {console.log(value)return '继续处理'}).catch((error) => {console.log(error) //输出失败})
控制台结果
let promise = new Promise((resolve, reject) => {setTimeout(() => reject('失败'), 1000)
}).then((value) => {console.log(value)return '继续处理'})
控制台结果
catch 既能处理 reject 回调,也能捕捉错误
3.finally() 方法
-
.finally(onFinally)
- onFinally :当 Promise 结束时调用的函数,它不接收任何参数,也不关心 Promise 的结果。在 Promise 结束时,无论它是成功还是失败,都会回调执行。这为在 Promise 链的末尾执行清理操作提供了一种方式,无论 Promise 的结果如何
- finally() 也返回一个新的 Promise 实例对象
let promise = new Promise((resolve, reject) => {setTimeout(() => resolve('成功'), 1000)// 或者 setTimeout(() => reject('失败'), 1000);
})
promise.then((value) => {console.log(value) // 如果 Promise 成功,则输出 '成功'return '继续处理' // 可以返回一个新的值或另一个 Promise}).catch((error) => {console.error(error) // 如果 Promise 失败,则输出错误信息}).finally(() => {console.log('Promise 结束了,无论成功还是失败')})
async/await
基本概念
Promise 虽然摆脱了回调地狱,但 then 链式调⽤的阅读负担还是存在的,为了优代码的阅读体验,增强了代码的可读性和可维护性,一种新的异步编程解决方案async/await诞生了。
async/await 是 JavaScript中用于处理异步操作的关键字对。它们使得异步代码看起来和写起来更像是同步代码,从而大大增强了代码的可读性和可维护性。这对关键字特别适用于处理如文件读写、网络请求等耗时的异步操作。
基本用法
async
- async关键字用于声明异步函数。这意味着该函数内部可以进行异步操作,比如发送网络请求、读取文件等。
- 异步函数内部可以使用
await
关键字来等待异步操作的完成。 - 异步函数会隐式地返回一个
Promise
对象。如果函数执行成功并且显式地返回了一个值,那么这个值会被封装成一个解析状态(fulfilled)的Promise
对象。如果没有显式地返回任何值,或者返回了一个非Promise
类型的值,JS会自动将这个值封成Promise.resolve(value)
(其中value
是函数的返回值或undefined
),并返回这个Promise
对象。 -
async function fun() {return 'async函数显示返回的值' } console.log(fun())
- 如果异步函数在执行过程中抛出了异常,那么这个异常会被捕获,并导致返回的
Promise
对象进入拒绝(rejected)状态,异常信息作为拒绝的原因。
await
await
关键字只能在async
函数内部使用。它用于等待一个Promise
完成。- 使用
await
时,async
函数的执行会暂停,直到等待的Promise
被解析(fulfilled)或拒绝(rejected)。 - 如果
Promise
被解析,await
表达式的结果就是Promise
解析的值。此时,async
函数的执行会继续进行。 - 如果
Promise
被拒绝,await
表达式会抛出一个异常。这个异常可以被async
函数内部的try...catch
语句捕获,也可以继续向上传播,直到被更高层级的错误处理机制捕获。
使用示例
假设我们有一个异步函数 fetchData
,它返回一个 Promise
,该 Promise
在一段时间后解析为一些数据:
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => {resolve('数据加载完成')}, 1000)})
}
使用 async/await
来调用这个函数:
async function loadData() {try {const data = await fetchData()console.log(data) // 输出: 数据加载完成} catch (error) {console.error('数据加载失败:', error)//throw error; // 可选:重新抛出错误,以便上层调用者可以处理 }
}
loadData()
在这个例子中,loadData
是一个 async
函数,它内部使用了 await
来等待 fetchData
函数返回的 Promise
完成。当 Promise
被解析时,await
表达式的结果(即 '数据加载完成'
)被赋值给 data
变量。如果 fetchData
函数抛出了一个错误(虽然在这个例子中没有),那么错误会被 catch
块捕获。
注意:
await
只能在async
函数内部使用。await
会暂停async
函数内部后续代码的执行,直到await
后的Promise
完成。await
可以用在任何返回Promise
的表达式上,不仅仅是函数调用。- 使用
async/await
可以使异步代码看起来更加直观和易于理解,但也要注意不要滥用,特别是在处理大量并发异步操作时。
async/await 的优势
-
代码清晰:
async/await
使得异步代码看起来和写起来更像是同步代码,提高了代码的可读性和可维护性。 -
错误处理:使用
try...catch
可以很容易地捕获和处理await
表达式抛出的异常,这与同步代码中的错误处理非常相似。 -
条件语句和循环:在
async
函数中,可以像处理同步代码一样使用if
语句、for
循环等控制流语句来等待Promise
完成。 -
中间件和组合:虽然
async/await
本身并不提供新的组合或中间件模式,但它与 Promises 很好地结合,使得可以轻松地组合多个异步操作。
---------------------------------------------------------------------------------------------------------------------------------
若有错误或描述不当的地方,烦请评论或私信指正,万分感谢 😃
相关文章:

异步编程(Promise详解)
目录 异步编程 回调函数 回调地狱 Promise 基本概念 Promise的特点 1.Promise是一种构造函数 2.Promise接收函数创建实例 3.Promise对象有三种状态 4.Promise状态转变不可逆 5.Promise 实例创建即执行 6.Promise可注册处理函数 7.Promise支持链式调用 Promise的静…...

DjangoORM注入分享
DjangoORM注入 简介 这篇文章中,分享一些关于django orm相关的技术积累和如果orm注入相关的安全问题讨论。 攻击效果同数据库注入 从Django-Orm开始 开发角度 Django ORM(Object-Relational Mapping)是Django框架中用于处理数…...

【HBZ分享】Redis各种类型的数据结构应用场景
String(字符串类型) 计数器: incr / decr, 比如商品库存,业务号的发号器业务数据key-value缓存, 缓存结果数据,提高网站性能,缓解DB压力分布式session会话, 集群环境下存储token鉴权信息分布式锁ÿ…...

anaconda创建并且配置pytorch(完整版)
📚博客主页:knighthood2001 ✨公众号:认知up吧 ** 🎃知识星球:【认知up吧|成长|副业】介绍** ❤️如遇文章付费,可先看看我公众号中是否发布免费文章❤️ 🙏笔者水平有限,欢迎各位大…...

高级java每日一道面试题-2024年8月10日-网络篇-你对跨域了解多少?
如果有遗漏,评论区告诉我进行补充 面试官: 你对跨域了解多少? 我回答: 跨域问题,即Cross-Origin Resource Sharing(CORS),是现代Web开发中一个非常重要的概念,涉及到浏览器的安全策略——同源策略(Same…...

AtCoder Beginner Contest 365 A~E
A.Leap Year(思维) 题意: 给你一个介于 1583 1583 1583和 2023 2023 2023之间的整数 Y Y Y。 求公历 Y Y Y年的天数。 在给定的范围内, Y Y Y年的天数如下: 如果 Y Y Y不是 4 4 4的倍数,则为 365 365 …...

多机部署, 负载均衡-LoadBalance
目录 1.负载均衡介绍 1.1问题描述 1.2什么是负载均衡 1.3负载均衡的一些实现 服务端负载均衡 客户端负载均衡 2.Spring Cloud LoadBalancer 2.1快速上手实现负载均衡 2.2负载均衡策略 自定义负载均衡策略 3.服务部署(Linux) 3.1服务构建打包…...

(回溯) LeetCode 78. 子集
原题链接 一. 题目描述 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集 (幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,2,3] 输出&…...

DQL数据查询语言(多表处理)—/—<7>
一、多表处理 当前有两个表,一个是学生表student,一个是分数表score student表字段名表示如下(共1000条数据): score表字段表示如下(共6000条数据): 1、求每个学生的总分 SELECT …...

力扣刷题总结
去年有段时间一直在刷题,进步神速,解决了以往刷完就忘的问题,这里总结下经验,给有需要的人参考下,核心观点就仨: 1. 打好数据结构与算法基础 2. 多刷题多练习 3. 形成自己的知识体系 下图是我梳理的知识体…...

BLDC ESC 无刷直流电子调速器驱动方式
BLDC ESC 无刷直流电子调速器驱动方式 1. 源由2. 驱动方法2.1 Trapezoidal 1202.2 Trapezoidal 1502.3 Sinusoidal 1802.4 Field-Orientated Control (FOC) 3. FOC(Field-Oriented Control)3.1 引入坐标系3.2 Clarke and Park变换Clarke 变换(…...

解决 IntelliJ IDEA 编译错误 “Groovyc: Internal groovyc error: code 1” 及 JVM 内存配置问题
在使用 IntelliJ IDEA 进行开发时,我们可能会遇到各种编译和运行错误,其中之一就是 Groovy 编译器错误(Groovyc: Internal groovyc error: code 1)或 JVM 内存不足错误。这类错误可能会影响开发效率,但通过调整 JVM 内…...

LeetCode.2940.找到Alice和Bob可以相遇的建筑
友情提示:这个方法并没有通过案例,只通过了944个案例(很难受),超时了,但是想着还是分享出来吧 题目描述: 给你一个下标从 0 开始的正整数数组 heights ,其中 heights[i] 表示第 i …...

OFD板式文件创建JAVA工具-EASYOFD 四、文字 Text
JAVA版本的OFD板式文件创建工具easyofd. 功能包含了图像、 图像、 文字、和模版页功能。同时也支持OFD文件的数字签名及验签,电子签章及验签。 本JAVA版本的easyofd使用原生方式创建板式文件,不依赖JAVA的SWT库。 项目地址:http://…...

【概念速通】李群 lie group
李群 lie group 概念速通 快速示例介绍:【引入】单位复数 (The unit complex numbers) 是李群 (lie group) 最简单的例子之一【进一步】SO(2): The 2D rotation matrices【Typical uses】SE(2): Pose of a robot in the plane Group & Lie Group 定义࿱…...

day_39
198. 打家劫舍 class Solution:def rob(self, nums: List[int]) -> int:if len(nums) 1:return nums[0]dp [0] * len(nums)dp[0], dp[1] nums[0], max(nums[0], nums[1])for i in range(2, len(nums)):dp[i] max(dp[i - 1], dp[i - 2] nums[i])return dp[len(nums) - …...

计算机系统层次结构
1.计算机系统的组成 计算机系统的组成硬件系统软件系统 2.计算机的硬件部分 2.1冯诺依曼机的结构特点: 图示: 1.五大部分由运算器(ALU),控制器(CU),存储器(主存辅存),输入设备,输出设备五大部分组成2.指…...

java语言特点
Java语言是一种广泛使用的编程语言,它具有以下几个显著的特点: 面向对象:Java是一种纯面向对象的语言,它支持类的封装、继承和多态等特性。面向对象的设计使得Java程序更加模块化,易于维护和扩展。 平台无关性…...

单元测试注解:@ContextConfiguration
ContextConfiguration注解 ContextConfiguration注解主要用于在Spring框架中加载和配置Spring上下文,特别是在测试场景中。 它允许开发者指定要加载的配置文件或配置类的位置,以便在运行时或测试时能够正确地构建和初始化Spring上下文。 基本用途和工…...

大数据-72 Kafka 高级特性 稳定性-事务 (概念多枯燥) 定义、概览、组、协调器、流程、中止、失败
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

MySQl 中对数据表的增删改查(基础)
MySQl 中对数据表的增删改查(基础) 新增演示插入一条数据插入多条数据 查询全列查询部分列查询查询关于列名的表达式查询时用别名查询去重后的结果查询排序后的结果条件查询比较运算符和逻辑运算符 分页查询 修改删除 黑白图是在命令行里的,彩…...

LVS知识点整理及实践
LVS知识点整理及实践 LVSlvs集群概念lvs概念lvs集群类型lvs-nat模型数据逻辑: lvs-DR模式数据传输和过程:特点: lvs-tun模式数据传输过程:特点: lvs-fullnet模式数据传输过程 lvs调度算法lvs调度算法类型lvs静态调度算法lvs动态调度算法4.15版本内核以后新增调度算法 ipvsadm命…...

Ubuntu gnome WhiteSur-gtk-theme类mac主题正确安装和卸载方式
目录 摘要目的安装和卸载特别说明 Ubuntu gnome WhiteSur-gtk-theme类mac主题正确安装和卸载方式 摘要 Ubuntu版本:ubuntu24.04 主题下载地址:https://github.com/vinceliuice/WhiteSur-gtk-theme 参考的安装教程:https://blog.51cto.com/u_…...

计算机毕业设计选题推荐-办公用品管理系统-Java/Python项目实战
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

计算机毕业设计选题推荐-网上考试系统-Java/Python项目实战
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

白骑士的Matlab教学基础篇 1.4 函数与脚本
系列目录 上一篇:白骑士的Matlab教学基础篇 1.3 控制流 函数和脚本是 MATLAB 编程中的基本组成部分,它们使得代码更加模块化、可重用和组织化。通过理解函数的定义与调用、参数与返回值,以及 MATLAB 脚本与批处理,可以显著提高编…...

Qt——多线程
一、QThread类 如果要设计多线程程序,一般是从QThread继承定义一个线程类,并重新定义QThread的虚函数 run() ,在函数 run() 里处理线程的事件循环。 应用程序的线程称为主线程,创建的其他线程称为工作线程。主线程的 start() 函数…...

技术周总结 08.05-08.11周日(scala git回滚)
文章目录 一、08.06 周二1.1) 问题01 mac安装 scala:1. 使用 Homebrew2. 使用 SDKMAN!其他注意事项1. 确认 Scala 安装位置2. 设置 PATH 环境变量对于 zsh (macOS Catalina 及更高版本默认使用 zsh):对于 bash (如果您使用的是 bash shell): 3. 验证安装 二、08.09 周五2.1&…...

ffmpeg 命令图片和视频转换
1、截图 ffmpeg -i d:\input.mp4 -ss 0:0:10 d:\output.jpg //指定输出分辨率 ffmpeg -i d:\input.mp4 -y -f image2 -ss 0:0:10 -vframes 1 -s 640x360 d:\output.jpg 2、视频分拆图片 ffmpeg -r 输入帧率 -i d:\input.mp4 -r 输出帧率 "d:\outputDir\frame_%04d.jp…...

力扣 | 动态规划 | 在字符串的应用 | 最长回文子串、最长回文子序列、单词拆分、编辑距离
文章目录 1.最长回文子串2.最长回文子序列3.单词拆分4.编辑距离5. 共同点和思路6. 各个问题的思路和扩展1. 最长回文子串2. 最长回文子序列3. 单词拆分4. 编辑距离 在解答字符串动态规划的应用时,我们需要非常注意一个问题: 有时候我们定义 d p [ i …...