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

前端 | 深入理解Promise

1. 引言

JavaScript 是一种单线程语言,这意味着它一次仅能执行一个任务。为了处理异步操作,JavaScript 提供了回调函数,但是随着项目处理并发任务的增加,回调地狱 (Callback Hell) 使异步代码很难维护。为此,ES6带来了Promise给了一种更清晰的异步操作模型。

2. 对Promise的理解

Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

(1)Promise的实例有三个状态:
  • Pending(进行中)
  • Resolved(已完成)
  • Rejected(已拒绝)
    当把一件事情交给promise时,它的状态就是Pending,任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
(2)Promise的实例有两个过程:
  • pending -> fulfilled : Resolved(已完成)
  • pending -> rejected:Rejected(已拒绝)

注意:一旦从进行状态变成为其他状态就永远不能更改状态了。

2.1 Promise的特点

  • 对象的状态不受外界影响。
    • promise对象代表一个异步操作,有三种状态,​pending​(进行中)、fulfilled​(已成功)、rejected​(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是promise这个名字的由来——“承诺”;
  • 一旦状态改变就不会再变,任何时候都可以得到这个结果。
    • promise对象的状态改变,只有两种可能:从 pending变为 fulfilled​,从 pending变为 rejected。这时就称为 resolved​(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。

2.2 Promise的缺点

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

3. Promise的基本用法

3.1 创建Promise对象

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve和 reject。

const promise = new Promise(function(resolve, reject) {// ... some codeif (/* 异步操作成功 */){resolve(value);} else {reject(error);}
});

使用resolve和reject方法

function testPromise(ready) {return new Promise(function(resolve,reject){if(ready) {resolve("hello world");}else {reject("No thanks");}});
};
// 方法调用
testPromise(true).then(function(msg){console.log(msg);
},function(error){console.log(error);
});

上面的代码的含义是给 testPromise方法传递一个参数,返回一个promise对象,如果为 true的话,那么调用promise对象中的 resolve()方法,并且把其中的参数传递给后面的 then第一个函数内,因此打印出 “hello world”, 如果为 false的话,会调用promise对象中的 reject()方法,则会进入 then的第二个函数内,会打印 No thanks;

3.2 Promise方法

(1)then()

第一个回调函数是Promise对象的状态变为 resolved时调用,第二个回调函数是Promise对象的状态变为 rejected时调用。其中第二个参数可以省略。

promise.then(function(value) {// success
}, function(error) {// failure
});

当要写有顺序的异步事件时,需要串行写:

let promise = new Promise((resolve,reject)=>{ajax('first').success(function(res){resolve(res);})
})
promise.then(res=>{return new Promise((resovle,reject)=>{ajax('second').success(function(res){resolve(res)})})
}).then(res=>{return new Promise((resovle,reject)=>{ajax('second').success(function(res){resolve(res)})})
}).then(res=>{})

事件没有顺序或者关系时,还如何写呢?可以使用 all 方法来解决。

(2)catch()

该方法相当于 then方法的第二个参数,指向 reject的回调函数。

p.then((data) => {console.log('resolved',data);
},(err) => {console.log('rejected',err);}
); 
// 或:
p.then((data) => {console.log('resolved',data);
}).catch((err) => {console.log('rejected',err);
});
(3)all()

all方法可以完成并行任务, 它接收一个数组,数组的每一项都是一个 promise对象。当数组中所有的 promise的状态都达到 resolved的时候,all方法的状态就会变成 resolved,如果有一个状态变成了 rejected,那么 all方法的状态就会变成 rejected。

let promise1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(1);},2000)
});
let promise2 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(2);},1000)
});
let promise3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(3);},3000)
});
Promise.all([promise1,promise2,promise3]).then(res=>{console.log(res);//结果为:[1,2,3] 
})
(4)race()

race方法和 all一样,接受的参数是一个每项都是 promise的数组,但是与 all不同的是,当最先执行完的事件执行完之后,就直接返回该 promise对象的值。如果第一个 promise对象状态变成 resolved,那自身的状态变成了 resolved;反之第一个 promise变成 rejected,那自身状态就会变成 rejected。

let promise1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(1);},2000)
});
let promise2 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(2);},1000)
});
let promise3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(3);},3000)
});
Promise.race([promise1,promise2,promise3]).then(res=>{console.log(res);//结果:2
},rej=>{console.log(rej)};
)

race方法有什么实际作用呢?当要做一件事,超过多长时间就不做了,可以用这个方法来解决:

Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})
(5)finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

4. 使用async/await代替Promise

4.1 对async/await的理解

async function testAsy(){return 'hello world';
}
let result = testAsy(); 
console.log(result)

在这里插入图片描述
async 函数返回的是一个 Promise 对象,所以在最外层不能用 await 获取其返回值的情况下,当然应该用原来的方式:then() 链来处理这个 Promise 对象,就像这样:

async function testAsy(){return 'hello world'
}
let result = testAsy() 
console.log(result)
result.then(v=>{console.log(v)   // hello world
})

那如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)。

联想一下 Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

注意:Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写,可以用于快速封装字面量对象或其他对象,将其封装成 Promise 实例。

4.2 async/await的优势

单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。仍然用 setTimeout 来模拟异步操作:

/*** 传入参数 n,表示这个函数执行的时间(毫秒)* 执行的结果是 n + 200,这个值将用于下一步骤*/
function takeLongTime(n) {return new Promise(resolve => {setTimeout(() => resolve(n + 200), n);});
}
function step1(n) {console.log(`step1 with ${n}`);return takeLongTime(n);
}
function step2(n) {console.log(`step2 with ${n}`);return takeLongTime(n);
}
function step3(n) {console.log(`step3 with ${n}`);return takeLongTime(n);
}

现在用 Promise 方式来实现这三个步骤的处理:

function doIt() {console.time("doIt");const time1 = 300;step1(time1).then(time2 => step2(time2)).then(time3 => step3(time3)).then(result => {console.log(`result is ${result}`);console.timeEnd("doIt");});
}
doIt();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1507.251ms

如果用 async/await 来实现呢,会是这样:

async function doIt() {console.time("doIt");const time1 = 300;const time2 = await step1(time1);const time3 = await step2(time2);const result = await step3(time3);console.log(`result is ${result}`);console.timeEnd("doIt");
}
doIt();

4.3 async/await对比Promise的优势

  • 代码读起来更加同步,Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担
  • Promise传递中间值⾮常麻烦,⽽async/await⼏乎是同步的写法,⾮常优雅
  • 错误处理友好,async/await可以⽤成熟的try/catch,Promise的错误捕获⾮常冗余
  • 调试友好,Promise的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,如果你在⼀个.then代码块中使⽤调试器的步进(step-over)功能,调试器并不会进⼊后续的.then代码块,因为调试器只能跟踪同步代码的每⼀步。

4.4 async/await如何捕获异常

使用 try…catch…

async function fn(){try{let a = await Promise.reject('error')}catch(error){console.log(error)}
}

5. 补充:Promise及其方法的手写

5.1 手写Promise

  • Promise 具有 pending(进行中)、fulfilled(已成功)和 rejected(已失败)三种状态,且状态不可逆。
  • new Promise(executor) 立即执行 executor 函数,并传入 resolve 和 reject,以控制 Promise 状态。
class MyPromise{constructor(executor){this.state = 'pending';this.value = undefined;  // 失败的值this.error = undefined;  // 成功的值this.onFulfilledCallbacks = [];  // 存储成功回调this.onRejectedCallbacks = [];  // 存储失败回调const resolve = (value)=>{if(this.state==='pending'){this.state = 'fulfilled';this.value = value;this.onFulfilledCallbacks.forEach(fn=>fn(value));  // 执行所有成功回调}};const reject = (error)=>{if(this.state==='pending'){this.state = 'rejected';this.error = error;this.onRejectedCallbacks.forEach(fn=>fn(error));}};try{executor(resolve,reject);}catch(error){reject(error);}}
}

5.2. 手写Promise.then

  • 在 Promise 变为 fulfilled 时调用 onFulfilled,并传入结果。
  • 在 Promise 变为 rejected 时调用 onRejected,并传入错误。
  • then 必须返回一个新的 Promise,支持链式调用。
Promise.prototype.then = function(onFulfilled,onRejected){return new Promise((resolve,reject)=>{if(this.state==='fulfilled'){try {const result = onFulfilled?onFulfilled(this.value):this.value;resolve(result);} catch (error) {reject(error);}}else if(this.state==='rejected'){try {const result = onRejected?onRejected(this.error):this.error;reject(result);} catch (error) {reject(error);}}else{this.onFulfilledCallbacks.push((value)=>{try {const result = onFulfilled ? onFulfilled(value) : value;resolve(result);} catch (error) {reject(error);}})this.onRejectedCallbacks.push((error) => {try {const result = onRejected ? onRejected(error) : error;reject(result);} catch (error) {reject(error);}});}})
}

注意:

  • Promise.then是实例方法,实例方法是挂载在prototype上的只能通过实例去调用,不能直接挂载在Promise上
  • 而all和race是静态方法,可以直接挂载在Promise上

5.3 手写Promise.all

1)核心思路
  1. 接收一个 Promise 实例的数组或具有 Iterator 接口的对象作为参数
  2. 这个方法返回一个新的 promise 对象,
  3. 遍历传入的参数,用Promise.resolve()将参数"包一层",使其变成一个promise对象
  4. 参数所有回调成功才是成功,返回值数组与参数顺序一致
  5. 参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all 的错误信息。
2)代码实现

一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了

function promiseAll(promises) {return new Promise(function(resolve, reject) {if(!Array.isArray(promises)){throw new TypeError(`argument must be a array`)}var resolvedCounter = 0;var promiseNum = promises.length;var resolvedResult = [];for (let i = 0; i < promiseNum; i++) {Promise.resolve(promises[i]).then(value=>{resolvedCounter++;resolvedResult[i] = value;if (resolvedCounter == promiseNum) {return resolve(resolvedResult)}},error=>{return reject(error)})}})
}
// test
let p1 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(1)}, 1000)
})
let p2 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(2)}, 2000)
})
let p3 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(3)}, 3000)
})
promiseAll([p3, p1, p2]).then(res => {console.log(res) // [3, 1, 2]
})

5.3 手写Promise.race

该方法的参数是 Promise 实例数组, 然后其 then 注册的回调方法是数组中的某一个 Promise 的状态变为 fulfilled 的时候就执行. 因为 Promise 的状态只能改变一次, 那么我们只需要把 Promise.race 中产生的 Promise 对象的 resolve 方法, 注入到数组中的每一个 Promise 实例中的回调函数中即可。

Promise.race = function (args) {return new Promise((resolve, reject)=>{for(let i = 0; i < args.length; i++){Promise.resolve(args[i]).then(resolve,reject)}})
}

相关文章:

前端 | 深入理解Promise

1. 引言 JavaScript 是一种单线程语言&#xff0c;这意味着它一次仅能执行一个任务。为了处理异步操作&#xff0c;JavaScript 提供了回调函数&#xff0c;但是随着项目处理并发任务的增加&#xff0c;回调地狱 (Callback Hell) 使异步代码很难维护。为此&#xff0c;ES6带来了…...

Visual Studio Code修改terminal字体

个人博客地址&#xff1a;Visual Studio Code修改terminal字体 | 一张假钞的真实世界 默认打开中断后字体显示如下&#xff1a; 打开设置&#xff0c;搜索配置项terminal.integrated.fontFamily&#xff0c;修改配置为monospace。修改后效果如下&#xff1a;...

自然语言处理-词嵌入 (Word Embeddings)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 词嵌入&#xff08;Word Embedding&#xff09;是一种将单词或短语映射到高维向量空间的技术&#xff0c;使其能够以数学方式表示单词之间的关系。词嵌入能够捕捉语义信息&#xff0c;使得相似的词在向量空间中具有…...

自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import precision_score, recall_score, f1_score# 数据准备 class1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4,…...

【论文笔记】Fast3R:前向并行muti-view重建方法

众所周知&#xff0c;DUSt3R只适合做稀疏视角重建&#xff0c;与sapnn3r的目的类似&#xff0c;这篇文章以并行的方法&#xff0c;扩展了DUSt3R在多视图重建中的能力。 abstract 多视角三维重建仍然是计算机视觉领域的核心挑战&#xff0c;尤其是在需要跨不同视角实现精确且可…...

谈谈你所了解的AR技术吧!

深入探讨 AR 技术的原理与应用 在科技飞速发展的今天&#xff0c;AR&#xff08;增强现实&#xff09;技术已经悄然改变了我们与周围世界互动的方式。你是否曾想象过如何能够通过手机屏幕与虚拟物体进行实时互动&#xff1f;在这篇文章中&#xff0c;我们将深入探讨AR技术的原…...

upload labs靶场

upload labs靶场 注意:本人关卡后面似乎相比正常的关卡少了一关&#xff0c;所以每次关卡名字都是1才可以和正常关卡在同一关 一.个人信息 个人名称&#xff1a;张嘉玮 二.解题情况 三.解题过程 题目&#xff1a;up load labs靶场 pass 1前后端 思路及解题&#xff1a;…...

搜索引擎友好:设计快速收录的网站架构

本文来自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/14.html 为了设计一个搜索引擎友好的网站架构&#xff0c;以实现快速收录&#xff0c;可以从以下几个方面入手&#xff1a; 一、清晰的目录结构与层级 合理划分内容&#xff1a;目录结构应…...

基于 oneM2M 标准的空气质量监测系统的互操作性

论文标题 英文标题&#xff1a; Interoperability of Air Quality Monitoring Systems through the oneM2M Standard 中文标题&#xff1a; 基于 oneM2M 标准的空气质量监测系统的互操作性 作者信息 Jonnar Danielle Diosana, Gabriel Angelo Limlingan, Danielle Bryan Sor…...

春晚舞台上的人形机器人:科技与文化的奇妙融合

文章目录 人形机器人Unitree H1的“硬核”实力传统文化与现代科技的创新融合网友热议与文化共鸣未来展望&#xff1a;科技与文化的更多可能结语 2025 年央视春晚的舞台&#xff0c;无疑是全球华人目光聚焦的焦点。就在这个盛大的舞台上&#xff0c;一场名为《秧BOT》的创意融合…...

零基础学习书生.浦语大模型-入门岛

第一关&#xff1a;Linux基础知识 Cursor连接服务器 使用Remote - SSH插件即可 注&#xff1a;46561&#xff1a;服务器端口号 运行指令 python hello_world.py端口映射 ssh -p 46561 rootssh.intern-ai.org.cn -CNg -L 7860:127.0.0.1:7860 -o StrictHostKeyCheckingno …...

Gurobi基础语法之 addConstr, addConstrs, addQConstr, addMQConstr

在新版本的 Gurobi 中&#xff0c;向 addConstr 这个方法中传入一个 TempConstr 对象&#xff0c;在模型中就会根据这个对象生成一个约束。更重要的是&#xff1a;TempConstr 对象可以传给所有addConstr系列方法&#xff0c;所以下面先介绍 TempConstr 对象 TempConstr TempC…...

数据结构---图的遍历

图的遍历(Travering Graph):从图的某一顶点出发&#xff0c;访遍图中的其余顶点&#xff0c;且每个顶点仅被访问一次&#xff0c;图的遍历算法是各种图的操作的基础。 复杂性:图的任意顶点可能和其余的顶点相邻接&#xff0c;可能在访问了某个顶点后&#xff0c;沿某条路径搜索…...

Qwen 模型自动构建知识图谱,生成病例 + 评价指标优化策略

关于数据库和检索方式的选择 AI Medical Consultant for Visual Question Answering (VQA) 系统&#xff1a;更适合在前端使用向量数据库&#xff08;如FAISS&#xff09;结合关系型数据库来实现图像和文本的检索与存储。因为在 VQA 场景中&#xff0c;你需要对患者上传的图像或…...

.Net Web API 访问权限限定

看到一个代码是这样的&#xff1a; c# webapi 上 [Route("api/admin/file-service"), AuthorizeAdmin] AuthorizeAdmin 的定义是这样的 public class AuthorizeAdminAttribute : AuthorizeAttribute {public AuthorizeAdminAttribute(){Roles "admin"…...

项目架构调整,切换版本并发布到中央仓库

文章目录 0.完成运维篇maven发布到中央仓库的部分1.配置server到settings.xml2.配置gpg 1.架构调整1.sunrays-dependencies&#xff08;统一管理依赖和配置&#xff09;1.作为单独的模块2.填写发布到中央仓库的配置1.基础属性2.基本配置3.插件配置 3.完整的pom.xml 2.sunrays-f…...

考试知识点位运算

深入理解位运算 在C编程的世界里&#xff0c;位运算作为一种直接对二进制位进行操作的运算方式&#xff0c;虽然不像加减乘除等算术运算那样广为人知&#xff0c;却在许多关键领域发挥着至关重要的作用。从底层系统开发到高效算法设计&#xff0c;位运算都展现出其独特的魅力与…...

matlab快速入门(2)-- 数据处理与可视化

MATLAB的数据处理 1. 数据导入与导出 (1) 从文件读取数据 Excel 文件&#xff1a;data readtable(data.xlsx); % 读取为表格&#xff08;Table&#xff09;CSV 文件&#xff1a;data readtable(data.csv); % 自动处理表头和分隔符文本文件&#xff1a;data load(data.t…...

Kafka中文文档

文章来源&#xff1a;https://kafka.cadn.net.cn 什么是事件流式处理&#xff1f; 事件流是人体中枢神经系统的数字等价物。它是 为“永远在线”的世界奠定技术基础&#xff0c;在这个世界里&#xff0c;企业越来越多地使用软件定义 和 automated&#xff0c;而软件的用户更…...

Python-列表

3.1 列表是什么 在Python中&#xff0c;列表是一种非常重要的数据结构&#xff0c;用于存储一系列有序的元素。列表中的每个元素都有一个索引&#xff0c;索引从0开始。列表可以包含任何类型的元素&#xff0c;包括其他列表。 # 创建一个列表my_list [1, 2, 3, four, 5.0]…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...