二. 网络请求&线程相关
1. 数据通信 ***
eventHub : 普通事件发布,订阅
- eventHub:提供了事件中心,提供订阅,取消订阅,触发事件的能力,同hap内通信,不跨线程
- eventHub.emit(数据标记,数据) ,触发事件
- eventHub.on(数据标记, ()=>{}) , 监听事件
emitter : 处理进程内,线程间事件 , 发送事件会放到事件队列 ,多hap通信方案
- emitter.emit({eventId:xx},数据) ,触发事件
- emitter.on({eventId:xx},()=>{}) , 监听事件
worker: 处理线程间事件,主要处理耗时事件
- 验证- 同hap
- 跨hap
2、项目中接口请求的数据,需要进行缓存吗?鸿蒙化处理过程
根据自己项目中的业务逻辑描述,MapKit需要将当前屏幕中展示的6个瓦片数据图片缓存到沙盒中,
杀掉进程后,断开网络,打开app会展示缓存的数据瓦片。
2.promise如何解决异步并发(Promise并发控制的实现方式)
异步并发涉及同时执行多个异步操作。可以使用 Promise.all
或 Promise.allSettled
方法来处理多个异步操作的并发执行。
-
使用
Promise.all
处理异步并发:Promise.all 可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组 ,而失败的时候则返回最先被 reject 失败状态的值。
Promse.all 在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
需要特别注意的是,Promise.all 获得的成功结果的数组里面的==数据顺序==和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
-
race
顾名思义,Promse.race 就是赛跑 的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
race 的使用场景就是,多台服务器部署了同样的服务端代码,假如我要获取一个商品列表接口,我可以在 race 中写上所有服务器中的查询商品列表的接口地址,哪个服务器响应快,就从哪个服务器拿数据。
-
使用
Promise.allSettled
处理异步并发:**Promise.allSettled()**
方法返回一个在所有给定的promise都已经fulfilled
或rejected
后的promise,并带有一个对象数组,每个对象表示对应的promise结果。当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个
promise
的结果时,通常使用它。顾名思义:allsettled,所有的都结束,不管结果。
参考链接:Promise异步并发控制https://www.javascriptcn.com/post/654fcbf27d4982a6eb8bf6e7
3.异步提交,代码封装 (Promise如何使用,有几种是否用方式,分别是什么)***
- then().catch()
- async/await+try{}catch(){}
异步提交(例如异步请求提交数据),可以封装一个函数来处理异步操作,使用 Promise 或者 async/await 提供异步编程的支持。
-
使用
Promise
封装异步提交:function asyncSubmit(data) { return new Promise((resolve, reject) => { // 模拟异步提交 setTimeout(() => { const success = true; // 模拟提交成功 if (success) { resolve('提交成功'); } else { reject('提交失败'); } }, 1000); }); } // 调用异步提交 asyncSubmit({ /* 数据 */ }) .then((result) => { console.log(result); }) .catch((error) => { console.error(error); });
-
使用async/await封装异步提交:
async function asyncSubmit(data) { return new Promise((resolve, reject) => { // 模拟异步提交 setTimeout(() => { const success = true; // 模拟提交成功 if (success) { resolve('提交成功'); } else { reject('提交失败'); } }, 1000); }); } // 调用异步提交 async function submit() { try { const result = await asyncSubmit({ /* 数据 */ }); console.log(result); } catch (error) { console.error(error); } } submit();
参考链接:
- promise封装异步操作https://blog.csdn.net/m0_71369720/article/details/132711656
- Promise、async、await,封装异步代码,解决回调地狱https://blog.csdn.net/akkigg/article/details/126369820
15.请介绍一下Async await ,await是否阻塞线程?
async/await
是 JavaScript 中处理异步代码的一种方式,它建立在 Promise 基础之上,提供了更清晰和易读的语法。使用 await
关键字可以暂停异步函数的执行,等待 Promise 对象的解决(resolve)。
await
并不会阻塞整个线程。当遇到 await
时,它会让出线程的执行,使得其他任务可以继续执行。在背后,await
会暂停当前函数的执行,等待 Promise 对象的状态发生变化。
参考链接:async/await详解https://blog.csdn.net/Zheng_xinle/article/details/108443274
1. 鸿蒙系统http在接口请求时,系统本身应该是开启子线程来请求,那么为什么在项目中还要使用taskpool开辟子线程呢
鸿蒙底层的http请求实现是在子线程中进行的,但针对于请求参数的编码与返回值的解析,这部分需要花费时间来处理的业务逻辑,还是建议使用taskpool开辟子线程来处理
参考答案二:
鸿蒙底层的http请求实现是在子线程中进行的。但在http在接口请求时,我们再开辟的子线程主要用于单次任务的执行,并对于请求返回值的解析,因为在返回大量时值解析是比较花费费时间的; 在多任务请求时TaskPool开辟的子线程可以执行密集型任务的开发,更加的灵活方便,
2. http数据请求采用什么方案? 请求参数类型是怎么设计的,如果是object, Object与object有啥区别?
已融入ppt: 进阶day01: 61
在进行网络请求前,您需要在module.json5文件中申明网络访问权限。因为HarmonyOS提供了一种访问控制机制即应用权限,用来保证这些数据或功能不会被不当或恶意使用。
{
"module" : {
"requestPermissions":[
{
"name": "ohos.permission.INTERNET"
}
]
}
}
-
导入http模块。
import http from '@ohos.net.http';
-
创建httpRequest对象。
使用createHttp()创建一个httpRequest对象,里面包括常用的一些网络请求方法,比如request、destroy、on('headerReceive')等。
let httpRequest = http.createHttp();
-
订阅请求头(可选)。
用于订阅http响应头,此接口会比request请求先返回,可以根据业务需要订阅此消息。
httpRequest.on('headersReceive', (header) => { console.info('header: ' + JSON.stringify(header)); });
-
发起http请求。
http模块支持常用的POST和GET等方法,封装在RequestMethod中。调用request方法发起网络请求,需要传入两个参数。第一个是请求的url地址,第二个是可选参数,类型为HttpRequestOptions,用于定义可选参数的类型和取值范围,包含请求方式、连接超时时间、请求头字段等。
请求参数通常以键值对的形式进行传递,其中参数类型可以是字符串、数字等基本类型。如果涉及到发送复杂的数据结构,比如JSON对象,那么请求参数的类型可能是一个对象(Object)。
Object:通常指的是 ArkTS 中的内置对象类型,用于表示键值对集合。
object:通常指的是 ArkTS 中的对象类型。在 ArkTS 中,对象是一种复合数据类型,它可以包含多个键值对。对象可以是基本类型的包装对象,也可以是用户自定义的对象。
参考链接:
- http数据请求参考:https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-http-0000001281201030
- 应用权限参考:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/accesstoken-overview-0000001333641125
3. 都说服务端响应整个流程慢,到底慢在哪里
服务端响应整个流程慢可能有多个原因,这需要进行系统性的性能分析以确定根本原因。以下是一些可能导致服务端响应慢的常见原因:
-
网络延迟: 如果服务端与客户端之间的网络延迟较高,数据在两者之间传输的时间将会增加。
-
服务器性能不足: 服务器硬件性能不足,或者服务器资源(CPU、内存、磁盘)被过度占用,可能导致响应时间延迟。
-
数据库性能: 如果应用程序需要从数据库中检索大量数据,或者数据库查询性能较差,会导致响应时间延迟。优化数据库查询、使用索引、缓存等可以改善这方面的问题。
-
第三方服务延迟: 如果应用程序依赖于外部的第三方服务,而这些服务的响应速度较慢,也会影响整体的响应时间。
-
未优化的代码: 代码的性能问题可能导致响应时间延迟。循环次数过多、未经优化的算法、内存泄漏等都可能影响代码的性能。
-
未优化的资源: 大量未经优化的静态资源(如图片、CSS、JavaScript)可能导致页面加载慢,从而影响整体的用户体验。
-
缺乏合适的缓存机制: 缺乏适当的缓存机制可能导致相同的请求重复执行相同的计算,增加响应时间。
为了准确定位服务端响应慢的原因,可以使用性能分析工具、日志分析工具以及监控工具进行详细的诊断。系统性的性能测试和监控可以帮助发现瓶颈,从而采取相应的优化策略。
参考链接:
- 应用服务器响应缓慢的原因及分析技巧 (应用服务器慢怎么分析)https://www.dbs724.com/450077.html
- 服务器运行慢的原因有哪些https://xkzzz.com/post/132119.html
4. 服务端响应期间会不会卡页面渲染
HarmonyOS(鸿蒙)是一个分布式操作系统,与传统的 Web 开发有所不同。在 Web 开发中,服务端响应慢可能会导致页面在浏览器中渲染时出现卡顿,因为浏览器通常会在主线程上执行 JavaScript 代码,包括处理响应数据和更新 DOM。
对于 HarmonyOS,服务端响应慢不会直接导致页面渲染的卡顿,因为 HarmonyOS 应用通常是本地应用,而不是在浏览器中运行的 Web 应用。HarmonyOS 应用的渲染通常是在本地设备上进行的,与服务端响应的速度关系不大。
但是,在 HarmonyOS 应用中,如果你的应用在进行网络请求时阻塞了主线程,例如在主线程上进行了同步的网络请求,那么这可能会导致 UI 的卡顿。因此,建议在进行网络请求时使用异步的方式,以避免阻塞主线程。
总体而言,HarmonyOS 应用的响应速度主要与本地设备的性能和网络请求的优化有关,与服务端响应慢是否会卡页面渲染关系较小。在应用开发中,建议合理使用异步操作、优化网络请求和合理设计本地业务逻辑,以提供更好的用户体验。
参考链接:
- 系统定义https://developer.harmonyos.com/cn/docs/documentation/doc-guides/harmonyos-overview-0000000000011903
- 技术特性https://developer.harmonyos.com/cn/docs/documentation/doc-guides/harmonyos-features-0000000000011907
- 系统安全https://developer.harmonyos.com/cn/docs/documentation/doc-guides/harmonyos-security-0000000000011934
5. 网络请求怎么使用 (你的项目中的网络请求用的是哪个api)***
- 官方提供的HTTP,我们进一步进行封装
- 三方提供的Axios
首先需要请求相应的权限。
- HTTP数据请求:通过HTTP发起一个数据请求。
- WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。
- Socket连接:通过Socket进行数据传输。
- 网络连接管理:网络连接管理提供管理网络一些基础能力,包括WiFi/蜂窝/Ethernet等多网络连接优先级管理、网络质量评估、订阅默认/指定网络连接状态变化、查询网络连接信息、DNS解析等功能。
- MDNS管理:MDNS即多播DNS(Multicast DNS),提供局域网内的本地服务添加、移除、发现、解析等能力。
6. 联系人中涉及到哪些数据请求,畅连caas接口提供方
联系人(contact)提供了联系人管理能力,包括添加联系人、删除联系人、更新联系人等。
HarmonyOS 提供了能力开发框架,你可以通过调用系统能力来获取联系人信息。如果联系人信息存储在设备本地,你可能需要使用数据存储和访问的 API 来获取这些信息。鸿蒙系统提供了分布式数据管理的能力,可以用于访问本地数据。 访问用户的敏感信息通常需要相应的权限。
关于 CaaS(Capability as a Service)接口提供方,鸿蒙系统提供了能力框架,使开发者可以调用系统能力。
参考链接:@ohos.contact(联系人)https://developer.harmonyos.com/cn/docs/documentation/doc-references-V2/js-apis-contact-0000001580026206-V2
7. axios请求参数如何写类型
在Axios中,如果想指定请求参数的类型,可以通过设置HTTP头部来实现。发送JSON数据,可以设置Content-Type
头部为application/json
。
告诉服务器正在发送JSON格式的数据。data
对象会被自动转换为JSON字符串。
参考链接:axios请求参数类型及传参方式https://blog.csdn.net/qq_51758070/article/details/134459741
8. 项目中接口请求的数据,需要进行缓存吗?鸿蒙化处理过程
根据自己项目中的业务逻辑描述,MapKit需要将当前屏幕中展示的6个瓦片数据图片缓存到沙盒中,杀掉进程后,断开网络,打开app会展示缓存的数据瓦片。
答:根据项目的实际情况决定,如有些数据长期可能不更改并且经常需要获取使用的数据(比如: 用户id, 登录态,token,以及项目中某些特殊页面的数据等)。还有就是有些应用或界面需要的做把文件缓存到本地再做对应的逻辑处理的情况也需要缓存。鸿蒙提供了多种方式的数据缓存,比如首选项、键值型数据库、关系型数据库等。
我们可以根据实际的数据类型进行选择对应的缓存方式。如:
键值型数据库:以键值对的形式存储数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格、员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。
关系型数据库:基于SQLite组件,适用于存储包含复杂关系数据的场景,比如一个班级的学生信息,需要包括姓名、学号、各科成绩等,又或者公司的雇员信息,需要包括姓名、工号、职位等,由于数据之间有较强的对应关系,复杂程度比键值型数据更高,此时需要使用关系型数据库来持久化保存数据。
9. taskpool开启子线程和promise的区别
taskpool开辟子线程能够充分利用现代手机设备多核配置,提高程序的并发性和运行效率;
Promise是在当前线程进行异步调用,可以避免阻塞主线程,保证程序的响应速度,提高用户体验;
具体使用场景:当需要执行I/O操作时,使用异步操作比使用线程+同步I/O操作更合适。 I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.Net Remoting等跨进程的调用。当需要长时间CPU运算的场合, 例如耗时较长的图形处理和算法执行时,建议使用子线程操作。
参考二:
taskpool:是多线程异步,是通过调用线程池内的线程去异步完成任务;
promise:是同一个线程在各个任务间进行切换,通过暂时挂起任务实现异步 ,异步代码会被挂起并在之后继续执行,并且同一时间只有一段代码执行。
10. 任务池(taskPool),worker,他们之间的区别及使用场景,实际项目怎么使用?
实现 | TaskPool | Worker |
---|---|---|
内存模型 | 线程间隔离,内存不共享。 | 线程间隔离,内存不共享。 |
参数传递机制 | 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。 | 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。 |
参数传递 | 直接传递,无需封装,默认进行transfer。 | 消息对象唯一参数,需要自己封装。 |
方法调用 | 直接将方法传入调用。 | 在Worker线程中进行消息解析并调用对应方法。 |
返回值 | 异步调用后默认返回。 | 主动发送消息,需在onmessage解析赋值。 |
生命周期 | TaskPool自行管理生命周期,无需关心任务负载高低。 | 开发者自行管理Worker的数量及生命周期。 |
任务池个数上限 | 自动管理,无需配置。 | 同个进程下,最多支持同时开启8个Worker线程。 |
任务执行时长上限 | 无限制。 | 无限制。 |
设置任务的优先级 | 不支持。 | 不支持。 |
执行任务的取消 | 支持取消任务队列中等待的任务。 | 不支持。 |
TaskPool中超长任务(大于3分钟)会被系统自动回收,如何避免超长任务?
将超大数据进行分段处理
[CPU密集型任务开发指导-使用多线程并发能力进行开发-并发-ArkTS语言基础类库-开发-HarmonyOS应用开发](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/cpu-intensive-task-development-0000001681369757-V3)
补充:
Worker:Worker中不能直接更新Page。Worker是否配置文件:在工程的[模块级build-profile.json5](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-building-configuration-0000001218440654#section6887184182020)文件的buildOption属性中添加配置信息。
taskPool与worker参数传递中数据类型支持:
基本类型数据、传递通过自定义class创建出来的object时,不会发生序列化错误
[@ohos.worker (启动一个Worker)-语言基础类库-ArkTS接口参考-ArkTS API参考-HarmonyOS应用开发](https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/js-apis-worker-0000001427902752-V3#ZH-CN_TOPIC_0000001574088505__序列化支持类型)
常见的一些开发场景及适用具体说明如下:
-
有关联的一系列同步任务。例如在一些需要创建、使用句柄的场景中,句柄创建每次都是不同的,该句柄需永久保存,保证使用该句柄进行操作,需要使用Worker。
-
需要频繁取消的任务。例如图库大图浏览场景,为提升体验,会同时缓存当前图片左右侧各2张图片,往一侧滑动跳到下一张图片时,要取消另一侧的一个缓存任务,需要使用TaskPool
-
大量或者调度点较分散的任务。例如大型应用的多个模块包含多个耗时任务,不方便使用8个Worker去做负载管理,推荐采用TaskPool。
11. 异步方法Promise,callback,promise是在哪个线程? 是否会卡主线程?实际开发中会优先使用哪种方式做回调?await是否会卡线程?
答:
Promise是在主线程执行的,不会卡主线程,是一种异步编程方式,用于处理异步操作。
await 不会卡线程,await 关键字会暂停当前异步函数的执行,并将控制权交还给事件循环,直到promise对象解析或拒绝。
通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。
优先使用promise。
12.promise如何使用?会不会阻塞UI线程(可了解下底层实现逻辑)
Promise 是 JavaScript 中用于处理异步操作的一种机制,它提供了更优雅的方式来处理异步代码,避免了回调地狱 。
- 使用new Promise() 创建
Promise
对象。 - 处理成功和失败,在执行器函数中进行异步操作,根据结果调用
resolve
或者reject
。 - 使用
then
和catch
处理结果,使用then
处理成功的情况,使用catch
处理失败的情况。
Promise不会阻塞UI线程,Promise设计的目的之一就是避免阻塞主线程。异步操作的执行不会阻塞 UI 线程,而是通过事件循环机制在后台执行。当异步操作完成后,它会调用相应的 resolve
或 reject
,然后触发注册的 then
或 catch
处理程序。
16. 子线程和主线程的消息传递
Worker开辟的子线程需要配合postMessage和onMessage实现消息传递;
TaskPool开辟的子线程通过回调传递进行传递;对持续订阅事件或单次订阅事件的处理、取消订阅事件、发送事件到事件队列等是通过[Emitter](https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/js-apis-emitter-0000001428061916-V2)发送和处理事件的。
-
子线程传递给主线程一个方法,是否支持?
不支持,自定义class的属性(如Function)无法通过序列化传递。
let func1 = function() { console.log("post message is function"); } // workerPort.postMessage(func1); 传递func1发生序列化错误
@ohos.worker (启动一个Worker)-语言基础类库-ArkTS接口参考-ArkTS API参考-HarmonyOS应用开发
17. 主线程上的数据对象序列化后传到子线程,子线程改变了对象的属性值,主线程跟着一起改变吗
不会,序列化是转换为字节码,已经和之前的对象没有关系了,就算反序列化成对象也是一个新对象。
- 序列化传输的数据量大小限制为16MB。
- 目前支持传输的数据对象可以分为普通对象、可转移对象、可共享对象、Native绑定对象四种。
18. then调用和await调用的区别
当使用Promise进行异步操作时,可以使用.then和await两种方式来调用异步接口;.then调用不阻塞当前线程,异步回调结束后会直接走到then中,await会等待当前异步方法执行结束才会继续往下执行。
参考答案二:
.then是promise接口的一个属性,可以通过.then方法链式的添加回调函数处理结果。
await是一个语法糖,是将后面的代码暂时挂起,等到任务执行完成后再继续执行。
-
在语法结构上也有不同:.then是通过方法链式调用处理Promise的结果,而await是异步函数内使用的关键字。
-
在处理错误的方式不同:.then是通过.catch方法来捕获Promise的拒绝结果,而await是通过try/catch块来捕获异步操作中的错误。
-
执行的顺序也不同:.then中的回调函数会在Promise完成后按顺序执行,而await会暂停当前函数的执行,直到等待Promise的解决或者拒绝。
19.鸿蒙在网络请求的时候如何校验CA(安全证书)
获取服务器证书->验证证书链->检查证书有效性->主机名验证
在鸿蒙系统中,这些步骤通常由底层网络库或框架来处理,而不需要应用程序开发者自己实现。
20.服务端响应期间调用三方库卡顿会不会卡页面渲染
过多引用三方库可能会造成卡顿
21.联系人中sdk的调用
联系人是通过调用full sdk(完整sdk)调用系统级别的功能,包含了public sdk(公共sdk)内容外还包含了系统底层的开发接口和功能,public sdk是包含了用于鸿蒙应用程序开发的基本组件和接口。适用于对资源要求较低、功能相对简单的应用场景。
22.promise异步并发遇到的场景有什么
比如并行请求多个资源的情况: 当需要同时获取多个资源时,可以使用Promise.all()方法将多个Promise对象包装成一个新的Promise对象,以便等待它们全部完成。
23.async是否允许修饰在生命周期方法前
语法不报错,但是不建议添加,可能会引起阻塞