对 Promise 的理解
Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步 操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调, 它比传统的解决方案回调函数和事件更合理和更强大。
所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束 的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一 个对象,从它可以获取异步操作的消息。Promise 提供统一的 API, 各种异步操作都可以用同样的方法进行处理。
- Promise 的实例有三个状态:
-
Pending(进行中)
-
Resolved(已完成)
-
Rejected(已拒绝)
当把一件事情交给 promise 时,它的状态就是 Pending,任务完成了 状态就变成了 Resolved、没有完成失败了就变成了 Rejected。
-
Promise 的实例有两个过程:
pending -> fulfilled: Resolved(已完成)
pending -> rejected: Rejected(已拒绝)注意:一旦从进行状态变成为其他状态就永远不能更改状态了。
Promise 的特点
对象的状态不受外界影响。promise 对象代表一个异步操作,有三种 状态,pending(进行中)、fulfilled(已成功)、rejected(已失 败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他 操作都无法改变这个状态,这也是 promise 这个名字的由来——“承 诺”;
一旦状态改变就不会再变,任何时候都可以得到这个结果。promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled,从 pending 变为 rejected。这时就称为 resolved(已定型)。如果改 变已经发生了,你再对 promise 对象添加回调函数,也会立即得到这 个结果。这与事件(event)完全不同,事件的特点是:如果你错过 了它,再去监听是得不到结果的。
Promise 实现
Promise 实现是通过js class编写,主要包括status、value、error、resolve、reject、then、catch、all、race、allSettled、any等组成。
- 状态
const PROMISE_STATUE_PENDING = "pending"; // 进行中const PROMISE_STATUE_FULFILLED = "fulfilled"; // 已完成const PROMISE_STATUE_REJECTED = "rejected"; // 已拒绝
- resolve 创建一个已解决的Promise对象,将给定的值作为其参数。
resolve = (value) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_FULFILLED;this.value = value;this.resFns?.forEach((fn) => {fn(this.value);});});}};
- reject 创建一个已拒绝的Promise对象,将给定的原因作为其参数
reject = (error) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_REJECTED;this.error = error;this.errFns.forEach((en) => {en(this.error);});});}};
- then 添加对Promise对象解决或拒绝时的处理程序
- 单个方法调用
constructor(executer) {this.statue = PROMISE_STATUE_PENDING;this.value = void 0;this.error = void 0;this.resFn;this.errFn;const resolve = ((value) => {if (this.status === PROMISE_STATUS_PENDING) {this.status = PROMISE_STATUS_FULFILLEDqueueMicrotask(() => { //queueMicrotask: 主线程执行完毕之后立马执行this.resfn(value)})}})const reject = ((error) => {if (this.status === PROMISE_STATUS_PENDING) {this.status = PROMISE_STATUS_REJECTEDqueueMicrotask(() => {this.errfn(error)})}})executer(this.resolve, this.reject);}then(resFn, errFn) {this.resFn = resFn;this.errFn = errFn;}
- 执行结果
const p1 = new myPromise((resolve, reject) => {resolve(111)reject(333333)
})
p1.then(res => { //最终打印 1111console.log(res);
}, err => {console.log(err);})
- 优化then 方法
官方给与的then 方法是可以进行数组传值和链式调用的,而目前我们写的是不支持。
this.resFns = [] //1.多次调用then 时用数组 保存this.errFns = []// 将then 方法修改为 then(resFn, errFn) {this.resfns.push(resFn);this.errFns.push(errFn);}// resolve修改为resolve = (value) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_FULFILLED;this.value = value;this.resFns?.forEach((fn) => {fn(this.value);});});}};// reject 修改为reject = (error) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_REJECTED;this.error = error;this.errFns.forEach((en) => {en(this.error);});});}};
优化后then的运行结果
p1.then(res => {console.log("res1:", res)
}, err => {console.log("err1:", err)
})
// 调用then方法多次调用
p1.then(res => {console.log("res2:", res)
}, err => {console.log("err2:", err)
})
运行结果:res2: 111 因为后面的.then 把前面的覆盖掉了 并不会执行res1 所在的代码块
*由此可见 then 方法调用时应该是个数组然后依次调用
下面改造我们的代码then,还需要优化执行resolve 时调用reject
then(resFn, errFn) {const defaultOnRejected = (err) => {throw err;};errFn = errFn || defaultOnRejected;const defaultOnFulFilled = (value) => {return value;};resFn = resFn || defaultOnFulFilled;return new MyPromise((resolve, reject) => {if (this.statue === PROMISE_STATUE_FULFILLED && !!resFn) {try {const value = resFn(this.value);resolve(value);} catch (error) {reject(error);}}if (this.statue === PROMISE_STATUE_REJECTED && !!errFn) {try {resolve(value);} catch (error) {reject(error);}}if (this.statue === PROMISE_STATUE_PENDING) {if (!!resFn) {this.resFns.push(() => {try {const value = resFn(this.value);resolve(value);} catch (error) {reject(error);}});}if (!!errFn) {this.errFns.push(() => {try {const value = errFn(this.error);resolve(value);} catch (error) {reject(error);}});}}});}
然后执行:
const p1 = new myPromise((resolve, reject) => {resolve(111);reject(333333);})p1.then(res => {console.log("res1:", res);}, err => {console.log("err1:", err);})// 调用then方法多次调用p1.then(res => {console.log("res2:", res);}, err => {console.log("err2:", err);})执行结果:res1: 111res2: 111
- catch 添加对Promise对象拒绝时的处理程序
// 添加对Promise对象拒绝时的处理程序。catch(errFn) {return this.then(undefined, errFn);}
- finally 添加对Promise对象解决或拒绝时的最终处理程序,无论Promise对象是否已被解决或拒绝。
finally(fn) {setTimeout(() => {fn();}, 0);}
- all 接收一个可迭代对象(如数组),并返回一个新的Promise对象。当所有Promise对象都已解决时,该Promise对象才将被解决,并返回一个包含所有解决值的数组。
// 通过类型判断当前数组中的方法或者对象是否为Promise 对象const isPromise = function(promise) {return (!!promise &&(typeof promise === "object" || typeof promise === "function") &&typeof promise.then === "function");};/*** 接收一个可迭代对象(如数组),并返回一个新的Promise对象。* 当所有Promise对象都已解决时,该Promise对象才将被解决,并返回一个包含所有解决值的数组。* @param {any[]} iterable* @desc 实际上多个对象同步执行时,就相当于把所有的方法重新进行Promise一次。* 当遍历到最后一个时,resolve 所有结果。* */MyPromise.all = function(iterable) {if (!(iterable instanceof Array)) {return console.log("传入参数必须是一个数组");}return new MyPromise((resolve, reject) => {let len = iterable.length;let count = 0;let results = new Array(len);for (let i = 0; i < len; i++) {let promise = iterable[i];count++;if (isPromise(promise)) {promise.then((res) => {results[i] = res;if (count === len) {resolve(results);}}).catch((err) => {reject(err);});} else if (typeof promise === "function") {results[i] = promise();} else {results[i] = promise;}}// 当数据的所有项都不是promise实例,我们就在这判断多一次,然后resolveif (count === len) {resolve(results);}});};
all 运行示例
(async function() {const res = MyPromise.all([new MyPromise((resolve) => {resolve(1);}),new MyPromise((resolve) => {resolve(2);}),() => {return 123;},88888,]);res.then((res) => {console.log(res);});})();运行结果: [1, 2, 123, 88888]
- race Promise.race(iterable) 传入多个对象,当任何一个执行完成后 resolve 结果
MyPromise.race = function(iterable) {if (!(iterable instanceof Array)) {return console.log("传入参数必须是一个数组");}return new MyPromise((resolve, reject) => {iterable.forEach((p) => {if (isPromise(p)) {p.then((value) => {resolve(value);}).catch((err) => {reject(err);});} else if (typeof p === "function") {resolve(p());} else {resolve(p);}});});
};
race 运行示例
(async function() {const res = MyPromise.race([new MyPromise((resolve) => {resolve(1);}),new MyPromise((resolve) => {resolve(2);}),]);res.then((res) => {console.log(res);});})();运行结果: 1
完整代码
// statusconst PROMISE_STATUE_PENDING = "pending"; // 进行中const PROMISE_STATUE_FULFILLED = "fulfilled"; // 已完成const PROMISE_STATUE_REJECTED = "rejected"; // 已拒绝class MyPromise {constructor(executer) {this.statue = PROMISE_STATUE_PENDING;this.value = void 0;this.error = void 0;this.resFns = [];this.errFns = [];executer(this.resolve, this.reject);}// 创建一个已解决的Promise对象,将给定的值作为其参数。resolve = (value) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_FULFILLED;this.value = value;this.resFns?.forEach((fn) => {fn(this.value);});});}};// 创建一个已拒绝的Promise对象,将给定的原因作为其参数。reject = (error) => {if (this.statue === PROMISE_STATUE_PENDING) {queueMicrotask(() => {if (this.statue !== PROMISE_STATUE_PENDING) return;this.statue = PROMISE_STATUE_REJECTED;this.error = error;this.errFns.forEach((en) => {en(this.error);});});}};// 添加对Promise对象解决或拒绝时的处理程序。then(resFn, errFn) {const defaultOnRejected = (err) => {throw err;};errFn = errFn || defaultOnRejected;const defaultOnFulFilled = (value) => {return value;};resFn = resFn || defaultOnFulFilled;return new MyPromise((resolve, reject) => {if (this.statue === PROMISE_STATUE_FULFILLED && !!resFn) {try {const value = resFn(this.value);resolve(value);} catch (error) {reject(error);}}if (this.statue === PROMISE_STATUE_REJECTED && !!errFn) {try {resolve(value);} catch (error) {reject(error);}}if (this.statue === PROMISE_STATUE_PENDING) {if (!!resFn) {this.resFns.push(() => {try {const value = resFn(this.value);resolve(value);} catch (error) {reject(error);}});}if (!!errFn) {this.errFns.push(() => {try {const value = errFn(this.error);resolve(value);} catch (error) {reject(error);}});}}});}// 添加对Promise对象拒绝时的处理程序。catch(errFn) {return this.then(undefined, errFn);}// 添加对Promise对象解决或拒绝时的最终处理程序,无论Promise对象是否已被解决或拒绝。finally(fn) {setTimeout(() => {fn();}, 0);}}const isPromise = function(promise) {return (!!promise &&(typeof promise === "object" || typeof promise === "function") &&typeof promise.then === "function");};/*** 接收一个可迭代对象(如数组),并返回一个新的Promise对象。* 当所有Promise对象都已解决时,该Promise对象才将被解决,并返回一个包含所有解决值的数组。* @param {any[]} iterable*/MyPromise.all = function(iterable) {if (!(iterable instanceof Array)) {return console.log("传入参数必须是一个数组");}return new MyPromise((resolve, reject) => {let len = iterable.length;let count = 0;let results = new Array(len);for (let i = 0; i < len; i++) {let promise = iterable[i];count++;if (isPromise(promise)) {promise.then((res) => {results[i] = res;if (count === len) {resolve(results);}}).catch((err) => {reject(err);});} else if (typeof promise === "function") {results[i] = promise();} else {results[i] = promise;}}// 当数据的所有项都不是promise实例,我们就在这判断多一次,然后resolveif (count === len) {resolve(results);}});};MyPromise.race = function(iterable) {if (!(iterable instanceof Array)) {return console.log("传入参数必须是一个数组");}return new MyPromise((resolve, reject) => {iterable.forEach((p) => {if (isPromise(p)) {p.then((value) => {resolve(value);}).catch((err) => {reject(err);});} else if (typeof p === "function") {resolve(p());} else {resolve(p);}});});};// const p1 = new MyPromise((resolve, reject) => {// console.log("状态pending");// resolve("22222");// reject("3333333");// });// p1.then((res) => {// console.log("res1:", res);// return "第二次的成功回调";// })// .catch((error) => {// console.log("err1:", error);// throw new Error("第二次的失败回调");// })// .finally(() => {// console.log("finally");// });// (async function() {// const res = MyPromise.all([// new MyPromise((resolve) => {// resolve(1);// }),// new MyPromise((resolve) => {// resolve(2);// }),// () => {// return 123;// },// 88888,// ]);// res.then((res) => {// console.log(res);// });// })();// (async function() {// const res = MyPromise.race([// new MyPromise((resolve) => {// resolve(1);// }),// new MyPromise((resolve) => {// resolve(2);// }),// ]);// res.then((res) => {// console.log(res);// });// })();
Promise 的缺点
无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始 还是即将完成)。
总结:
Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise 是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。 一个 Promise 实例有三种状态,分别是 pending、resolved 和 rejected,分别代表了进行中、已成功和已失败。实例的状态只能由 pending 转变 resolved 或者 rejected 状态,并且状态一经改变, 就凝固了,无法再被改变了。
状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在 异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原 型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的 改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的 末尾执行。
注意:在构造 Promise 的时候,构造函数内部的代码是立即执行的。
相关文章:
对 Promise 的理解
Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步 操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调, 它比传统的解决方案回调函数和事件更合理和更强大。 所谓 Promise,简单说就…...
Vuex:Vue.js应用程序的状态管理模式
介绍 在Vue.js应用程序中,随着项目复杂度的增加,组件之间的数据共享和管理变得困难。为了解决这个问题,Vue.js提供了一个名为Vuex的状态管理模式。Vuex可以帮助我们更有效地组织、管理和共享应用程序的状态。 什么是Vuex? Vuex…...

Unity之ShaderGraph 节点介绍 Utility节点
Utility 逻辑All(所有分量都不为零,返回 true)Any(任何分量不为零,返回 true)And(A 和 B 均为 true)Branch(动态分支)Comparison(两个输入值 A 和…...

springboot()—— swagger
零、一张图读懂swagger 懂了,这玩意就是用swagger搞出来的! 就是一个后端开发自测的东西嘛! 一、概念 存在即合理,我们看一下swagger诞生的原因:在前后端分离的架构中,前端新增一个字段,后端就…...

Java课题笔记~ 关联映射
一、MyBatis关联查询 在关系型数据库中,表与表之间存在着3种关联映射关系,分别为一对一、一对多、多对多。 一对一:一个数据表中的一条记录最多可以与另一个数据表中的一条记录相关。列如学生与学号就属于一对一关系。 一对多:主…...

一零六七、JVM梳理
JVM? Java虚拟机,可以理解为Java程序的运行环境,可以执行Java字节码(Java bytecode)并提供了内存管理、垃圾回收、线程管理等功能 java内存区域划分?每块内存中都对应什么? 方法区:类的结构信息、常量池、…...

【CSS】网格布局(简单布局、网格合并、网格嵌套)
文章目录 CSS网格布局(Grid Layout)1. 简单布局2. 网格合并3. 网格嵌套4. 总结 CSS网格布局(Grid Layout) CSS网格布局(Grid Layout)是一种强大且灵活的CSS布局系统,允许开发者以网格形式组织和…...

06 Ubuntu22.04上的miniconda3安装、深度学习常用环境配置
下载脚本 我依然是在清华镜像当中寻找的脚本。这里找脚本真的十分方便,我十分推荐。 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh 下载十分快速,10秒解决问题 运行miniconda3安装脚本 赋予执…...

【CSS3】CSS3 动画 ② ( 动画序列 | 使用 from 和 to 定义动画序列 | 定义多个动画节点 | 代码示例 )
文章目录 一、动画序列二、代码示例 - 使用 from 和 to 定义动画序列三、代码示例 - 定义多个动画节点 一、动画序列 定义动画时 , 需要设置动画序列 , 下面的 0% 和 100% 设置的是 动画 在 运行到某个 百分比节点时 的 标签元素样式状态 ; keyframes element-move { 0% { tr…...

最优化:建模、算法与理论
最优化:建模、算法与理论 目前在学习 最优化:建模、算法与理论这本书,来此记录一下,顺便做一些笔记,在其中我也会加一些自己的理解,尽量写的不会那么的条条框框(当然最基础的还是要有ÿ…...

拿捏--->打印菱形
文章目录 题目描述算法思路代码示例 题目描述 在屏幕上输出以下图案: 算法思路 代码示例 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() {int n;scanf("%d", &n);//上半部分菱形for (int i 0; i < n; i) //上半部分…...

【SpringBoot笔记】定时任务(cron)
定时任务就是在固定的时间执行某个程序,闹钟的作用。 1.在启动类上添加注解 EnableScheduling 2.创建定时任务类 在这个类里面使用表达式设置什么时候执行 cron 表达式(也叫七子表达式),设置执行规则 package com.Lijibai.s…...

Redis单机,主从,哨兵,集群四大模式
Redis 单机模式 Redis 单机模式是指 Redis 数据库在单个服务器上以独立的、单一的进程运行的模式。在这种模式下,Redis 不涉及数据分片或集群配置,所有的数据和操作都在一个实例中进行。以下是关于 Redis 单机模式的详细介绍: 单一实例&#…...

2023年8月份华为H12-811更新了
801、[单选题]178/832、在系统视图下键入什么命令可以切换到用户视图? A quit B souter C system-view D user-view 试题答案:A 试题解析:在系统视图下键入quit命令退出到用户视图。因此答案选A。 802、[单选题]“网络管理员在三层交换机上创建了V…...

[K8S:命令执行:权限异常:解决篇]:通过更新kubeconfig配置相关信息
文章目录 一:场景复现:1.1:关键信息:1.2:全异常日志输出: 二:解决流程:2.1:更新 kubeconfig:2.1.1:执行命令: 2.2:再次执行…...

帆软设计器报表加载不出折线图的原因
最近在用帆软设计器做可视化图表。偶有遇到因为数据集的字段类型导致加载不出折线,现记录如下。做报表的同行可以参考。 数据库使用了 Oracle 11g。数据集的 SQL 代码片是之前用在另一个单元格报表里面的。页面上有一个率是直接计算得出,我为了方便、就…...
[QCA6174]sdx12平台WiFi QCA6174在驱动加载的时候增加模块参数方法
需求描述 由于开发需要,有时候需要在驱动模块加载的时候增加一个参数,传递给到驱动使用 平台描述 Qualcomm SDX12+QCA6174平台 驱动信息 [ 112.281429] wlan: loading driver v4.0.11.213X [ 112.340262] msm_pcie_enable: PCIe: Assert the reset of endpoint of RC0. …...

Ajax-AJAX请求的不同发送方式
🥔:你一定能成为想要成为的人 发送AJAX请求不同方式 发送AJAX请求不同方式1、jQuery发送AJAX请求2、axios发送AJAX请求(重点)3、fetch发送AJAX请求 发送AJAX请求不同方式 1、jQuery发送AJAX请求 首先需要jquery的js文件…...

简易图书管理系统(面向对象思想)
目录 前言 1.整体思路 2.Book包 2.1Book类 2.2BookList类 3.user包 3.1User类 3.2NormalUser类 3.3AdminUser类 4.operation 4.1IOPeration接口 4.2ExitOperation类 4.3FindOperation类 4.4ShowOperation类 4.5AddOperation类 4.6DelOperation类 4.7BorrowOpera…...

C++ 函数模板与类模板
C最重要的特性之一就是代码重用,为了实现代码重用,代码必须具有通用性。通用代码应不受数据类型的影响,并且可以自动适应数据类型的变化。这种程序设计类型称为参数化程序设计。模板是C支持参数化程序设计的工具,通过它可以实现参…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...