IT评测·应用市场-qidao123.com技术社区

标题: Harmony口试题 [打印本页]

作者: 星球的眼睛    时间: 2025-1-12 22:42
标题: Harmony口试题
收集官网faq:文档中心
一. ArkTS&ArkUI

1. 根本理论

  1. 鸿蒙相关的生命周期都有哪些?

UIAbility生命周期nCreate、onWindowStageCreate、onForeground、onBackground、onWindowStageDestroy、onDestroy。


页面生命周期:onPageShow、onPageHide、onBackPress。

组件生命周期:aboutToAppear(发起网络请求)、aboutToDisappear。

按返回键页面执行生命周期方法:

返回页面不走aboutToAppear:

aboutToAppear和onAppear的区别?

2. ArkUI的两大开发范式是什么,区别是什么 ***



 
3. 项目使用的是harmoneyos还是openharmoney,区别是啥

我们公司的项目使用的是HarmonyOS。

HarmonyOS:OpenHarmony+闭源应用和华为移动服务HMS(比如应用市场,视频,音乐等app)
Andoird:aosp(android open source project) + GMS(Google Mobile Service)
3. 关于context相关得内容有哪些 , 他们的区别?

各类Context的继承关系:

使用:
理论:
基类Context提供了获取应用文件路径的本领,ApplicationContext、AbilityStageContext、UIAbilityContext和ExtensionContext均继承该本领。应用文件路径属于应用沙箱路径,详细请参见应用沙箱目次。
上述各类Context获取的应用文件路径有所不同。
通过ApplicationContext==获取应用级别的应用文件路径==,此路径是应用全局信息推荐的存放路径,这些文件会跟随应用的卸载而删除。
  1. import common from '@ohos.app.ability.common';
  2. @Entry
  3. @Component
  4. struct Page_Context {
  5.  private context = getContext(this) as common.UIAbilityContext;
  6.  build() {
  7.    ...
  8.    Button()
  9.      .onClick(() => {
  10.        let applicationContext = this.context.getApplicationContext();
  11.        let cacheDir = applicationContext.cacheDir;//<路径前缀>/<加密等级>/base/cache
  12.        let tempDir = applicationContext.tempDir;
  13.        let filesDir = applicationContext.filesDir;
  14.        let databaseDir = applicationContext.databaseDir;
  15.        let bundleCodeDir = applicationContext.bundleCodeDir;
  16.        let distributedFilesDir = applicationContext.distributedFilesDir;
  17.        let preferencesDir = applicationContext.preferencesDir;
  18.        // 获取应用文件路径
  19.        let filePath = tempDir + 'test.txt';
  20.        hilog.info(DOMAIN_NUMBER, TAG, `filePath: ${filePath}`);
  21.        if (filePath !== null) {
  22.          promptAction.showToast({
  23.          message: filePath
  24.          });
  25.        }
  26.      })
  27.   }
  28. }
复制代码
通过AbilityStageContext、UIAbilityContext、ExtensionContext==获取HAP级别的应用文件路径==。此路径是HAP相关信息推荐的存放路径,这些文件会跟随HAP的卸载而删除,但不会影相应用级别路径的文件,除非该应用的HAP已全部卸载。
  1. import common from '@ohos.app.ability.common';
  2. @Entry
  3. @Component
  4. struct Page_Context {
  5.  private context = getContext(this) as common.UIAbilityContext;
  6.  build() {
  7.    ...
  8.    Button()
  9.      .onClick(() => {
  10.        let cacheDir = this.context.cacheDir;//<路径前缀>/<加密等级>/base/haps/<module-name>/cache
  11.        let tempDir = this.context.tempDir;
  12.        let filesDir = this.context.filesDir;
  13.        let databaseDir = this.context.databaseDir;
  14.        let bundleCodeDir = this.context.bundleCodeDir;
  15.        let distributedFilesDir = this.context.distributedFilesDir;
  16.        let preferencesDir = this.context.preferencesDir;
  17.        // 获取应用文件路径
  18.        let filePath = tempDir + 'test.txt';
  19.      })
  20.   }
  21. }
复制代码
 
4. arkts中哪些类不能被继承, 口试官关注点是组件是否可以继承?(组件是否可以被继承)

组件不能被继承,被@compent修饰的自界说组件不能被继承,只能引用,或者对外暴露方法。
官网解释:

5.先容Stage模型和FA模型

 
2. 装饰器

1. 你使用过哪些装饰器,分别阐述一下他们得作用 ***


2. 有用过@Styles,@Extend,@Builder装饰器么?


3. 还用过其他装饰器么?

1. Provide和Consume
2. ObjectLink和Observed

3. Watch
概述
代码:
  1. @Component
  2. struct TotalView {
  3.  @Prop @Watch('onCountUpdated') count: number = 0;
  4.  @State total: number = 0;
  5.  // 该函数是自定义组件的成员函数
  6.  // @Watch 回调
  7.  // propName是被watch的属性名
  8.  // 多个状态绑定同一个@Watch回调时,通过propName区分到底是哪个状态改变了
  9.  onCountUpdated(propName: string): void {
  10.    this.total += this.count;
  11.   }
  12.  build() {
  13.    Text(`Total: ${this.total}`)
  14.   }
  15. }
  16. @Entry
  17. @Component
  18. struct CountModifier {
  19.  @State count: number = 0;
  20.  build() {
  21.    Column() {
  22.      Button('add to basket')
  23.        .onClick(() => {
  24.          this.count++
  25.        })
  26.      TotalView({ count: this.count })
  27.    }
  28.   }
  29. }
复制代码
 
 
3. 数据存储

1. LocalStorage和AppStorage的区别,和对应的装饰器以及PersistentStorage ***

LocalStorage
页面级UI状态存储,通常用于UIAbility内、页面间的状态共享。
localStorage是页面级数据存储,在页面中创建实例,组件中使用@LocalStorageLink和@LocalStorageProp装饰器修饰对应的状态变量,绑定对应的组件使用比状态属性更灵活
  1. //应用逻辑使用LocalStorage
  2. let para: Record<string,number> = { 'PropA': 47 };
  3. let storage: LocalStorage = new LocalStorage(para); // 创建新实例并使用给定对象初始化 , 创建实例存储数据
  4. let propA: number | undefined = storage.get('PropA') // propA == 47 ,get()获取数据
  5. //link():如果给定的propName在LocalStorage实例中存在,则返回与LocalStorage中propName对应属性的双向绑定数据。 (双向同步)
  6. let link1: SubscribedAbstractProperty<number> = storage.link('PropA'); // link1.get() == 47
  7. let link2: SubscribedAbstractProperty<number> = storage.link('PropA'); // link2.get() == 47
  8. //prop():如果给定的propName在LocalStorage中存在,则返回与LocalStorage中propName对应属性的单向绑定数据。  (单向同步)
  9. let prop: SubscribedAbstractProperty<number> = storage.prop('PropA'); // prop.get() == 47
  10. link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48 //双向同步
  11. prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48 //单向同步
  12. link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
复制代码

  1. //UI使用LocalStorage
  2. //除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。
  3. // 创建新实例并使用给定对象初始化
  4. let para: Record<string, number> = { 'PropA': 47 };
  5. //这个变量一般就定义在某个@Entry组件的上方**
  6. let storage: LocalStorage = new LocalStorage(para);
  7. @Component
  8. struct Child {
  9. // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
  10. @LocalStorageLink('PropA') storageLink2: number = 1;
  11. build() {
  12.   Button(`Child from LocalStorage ${this.storageLink2}`)
  13.     // 更改将同步至LocalStorage中的'PropA'以及Parent.storageLink1
  14.     .onClick(() => {
  15.       this.storageLink2 += 1
  16.     })
  17. }
  18. }
  19. // 使LocalStorage可从@Component组件访问
  20. @Entry(storage)//storage是上边定义的变量**
  21. @Component
  22. struct Parent {
  23. // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
  24. @LocalStorageLink('PropA') storageLink1: number = 1;
  25. build() {
  26.   Column({ space: 15 }) {
  27.     Button(`Parent from LocalStorage ${this.storageLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
  28.       .onClick(() => {
  29.         this.storageLink1 += 1
  30.       })
  31.     // @Component子组件自动获得对CompA LocalStorage实例的访问权限。
  32.     Child()
  33.   }
  34. }
  35. }
  36. //上述代码:如果将LocalStorageLink改为LocalStorageProp就由双向变为了单向
复制代码

AppStorage
AppStorage是进程级数据存储(==应用级的全局状态共享==),进程启动时自动创建了唯一实例,在各个页面组件中@StorageProp和@StorageLink装饰器修饰对应的状态变量。
  1. //AppStorage是单例,它的所有API都是静态的
  2. AppStorage.setOrCreate('PropA', 47);
  3. let propA: number | undefined = AppStorage.get('PropA') // propA in AppStorage == 47
  4. let link1: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link1.get() == 47
  5. let link2: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link2.get() == 47
  6. let prop: SubscribedAbstractProperty<number> = AppStorage.prop('PropA'); // prop.get() == 47
  7. link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
  8. prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
  9. link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
  10. AppStorage.get<number>('PropA') // == 49
  11. link1.get() // == 49
  12. link2.get() // == 49
  13. prop.get() // == 49
复制代码

  1. AppStorage.setOrCreate('PropA', 47);
  2. @Entry(storage)
  3. @Component
  4. struct CompA {
  5.  @StorageLink('PropA') storageLink: number = 1;
  6.  build() {
  7.    Column({ space: 20 }) {
  8.      Text(`From AppStorage ${this.storageLink}`)
  9.        .onClick(() => {
  10.          this.storageLink += 1
  11.        })
  12.    }
  13.   }
  14. }
复制代码

 
补充:
localStorage和appStorage数据存取都是在主线程进行的,且api只提供了同步接口,存取数据时要注意数据的巨细。


 
PersistentStorage
PersistentStorage将选定的AppStorage属性保存在设备磁盘上。应用步伐通过API,以决定哪些AppStorage属性应借助PersistentStorage长期化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。
PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,别的另有一些接口可以用于管理长期化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的
从AppStorage中访问PersistentStorage初始化的属性
 
 
2.数据存储怎么存?都用过什么数据存储?用户首选项,键值型数据库,关系数据库

首选项
用户首选项(Preferences):提供了==轻量级配置数据的长期化本领==,并支持订阅数据变化的关照本领。不支持分布式同步,常用于保存==应用配置信息、用户偏好设置==等。
运作机制:

束缚限制:

代码:
  1. import dataPreferences from '@ohos.data.preferences';
  2. //1. 获取preference
  3. private preferences: dataPreferences.Preferences =  dataPreferences.getPreferencesSync(this.context, { name: 'myStore' });
  4. //2. 保存数据
  5. this.preferences.putSync('key', value);
  6. //3. 持久化数据
  7. this.preferences.flush()
  8. //4. 获取数据
  9. let result = this.preferences.getSync("key",16)
  10. this.changeFontSize = Number(result)
复制代码
键值型数据库
键值型数据库存储键值对情势的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应代价、员工工号及今日是否已出勤等,由于数据复杂度低,更轻易兼容不同数据库版本和设备范例,因此推荐使用键值型数据库长期化此类数据。
束缚:

剩余内容:文档中心
关系型数据库
关系型数据库基于SQLite组件,适用于存储包含==复杂关系数据==的场景,比如一个班级的弟子信息,需要包罗姓名、学号、各科结果等,又或者公司的雇员信息,需要包罗姓名、工号、职位等,由于数据之间有较强的对应关系,复杂水平比键值型数据更高,此时需要使用关系型数据库来长期化保存数据。
运作机制:

束缚:

代码:
  1. import relationalStore from '@ohos.data.relationalStore'
  2. import { common } from '@kit.AbilityKit'
  3. export  class DBUtils {
  4.  // 数据库名称
  5.  private tableName: string = 'accountTable'
  6.  // 建表语句
  7.  private sqlCreate: string = 'CREATE TABLE IF NOT EXISTS accountTable(id INTEGER PRIMARY KEY AUTOINCREMENT, accountType INTEGER, ' +
  8.    'typeText TEXT, amount INTEGER)'
  9.  // 表字段
  10.  private columns: string[] = ['id', 'accountType', 'typeText', 'amount']
  11.  // 数据库核心类
  12.  private rdbStore: relationalStore.RdbStore | null = null
  13.  // 数据库配置
  14.  DB_CONFIG: relationalStore.StoreConfig = {
  15.    name: 'RdbTest.db', // 数据库文件名
  16.    securityLevel: relationalStore.SecurityLevel.S1, // 数据库安全级别
  17.   };
  18.  /**
  19.   * 获取rdb
  20.   * @param context:上下文
  21.   * @param callback:回调函数,我们第一次获取数据时,需要在获取到rdb之后才能获取,所以有此回调
  22.   */
  23.  getRdbStore(context: common.UIAbilityContext, callback: Function) {
  24.    relationalStore.getRdbStore(context, this.DB_CONFIG, (error, store) => {
  25.      if (this.rdbStore !== null) {
  26.        //如果已经有rdb,直接建表
  27.        store.executeSql(this.sqlCreate)
  28.        return
  29.      }
  30.      //保存rdb,下边会用
  31.      this.rdbStore = store
  32.      //建表
  33.      store.executeSql(this.sqlCreate)
  34.      console.log("test", "successed get dbStore")
  35.      if (callback) callback()
  36.    })
  37.   }
  38.  /**
  39.   * 插入数据
  40.   * @param data:数据对象
  41.   * @param callback:回调函数,这里的结果是通过回调函数返回的(也可使用返回值)
  42.   */
  43.  insertData(data: AccountData, callback: Function) {
  44.    //将数据对象,转换为ValuesBucket类型
  45.    const valueBucket: relationalStore.ValuesBucket = generateBucket(data);
  46.    // 调用insert插入数据
  47.    this.rdbStore && this.rdbStore.insert(this.tableName, valueBucket, (err, res) => {
  48.      if (err) {
  49.        console.log("test,插入失败", err)
  50.        callback(-1)
  51.        return
  52.      }
  53.      console.log("test,插入成功", res)
  54.      callback(res) //res为行号
  55.    })
  56.   }
  57.  /**
  58.   * 获取数据
  59.   * @param callback:接收结果的回调函数
  60.   */
  61.  query(callback: Function) {
  62.    //predicates是用于添加查询条件的
  63.    let predicates = new relationalStore.RdbPredicates(this.tableName)
  64.    // 查询所有,不需要条件
  65.    // predicates.equalTo("字段",数据)
  66.    this.rdbStore && this.rdbStore.query(predicates, this.columns, (error, resultSet: relationalStore.ResultSet) => {
  67.      if(error){
  68.        console.log("test,获取数据失败",JSON.stringify(error))
  69.        return
  70.      }
  71.      let count: number = resultSet.rowCount
  72.      console.log("test","数据库中数据数量:"+count) //没数据时返回-1或0
  73.      if (count <= 0 || typeof count === 'string') {
  74.        callback([])
  75.        return
  76.      }
  77.      let result: AccountData[] = []
  78.      //上来必须调用一次goToNextRow,让游标处于第一条数据,while(resultSet.goToNextRow())是最有写法
  79.      while(resultSet.goToNextRow()) {
  80.        let accountData:AccountData = {id:0,accountType:0,typeText:'',amount:0}
  81.        accountData.id = resultSet.getDouble(resultSet.getColumnIndex('id'));
  82.        accountData.typeText = resultSet.getString(resultSet.getColumnIndex('typeText'))
  83.        accountData.accountType = resultSet.getDouble(resultSet.getColumnIndex('accountType'))
  84.        accountData.amount = resultSet.getDouble(resultSet.getColumnIndex('amount'))
  85.        result.push(accountData)
  86.      }
  87.      callback(result)
  88.      resultSet.close()//释放数据集内容
  89.    })
  90.   }
  91. }
  92. function generateBucket(account: AccountData): relationalStore.ValuesBucket {
  93.  let obj: relationalStore.ValuesBucket = {};
  94.  obj.accountType = account.accountType;
  95.  obj.typeText = account.typeText;
  96.  obj.amount = account.amount;
  97.  return obj;
  98. }
  99. export class AccountData {
  100.  id: number = -1;
  101.  accountType: number = 0;
  102.  typeText: string = '';
  103.  amount: number = 0;
  104. }
复制代码
使用代码:(部分代码,从HelloDataManager中copy的)
  1. // 数据库工具类
  2.  private dbUitls: DBUtils = new DBUtils()
  3. // 界面打开时,查询数据,展示胡静
  4.  aboutToAppear(): void {
  5.    this.dbUitls.getRdbStore(this.context, () => {
  6.      this.queryData()
  7.    })
  8.   }
  9.  // 查询数据方法
  10.  queryData(){
  11.    this.dbUitls.query((result: AccountData[]) => {
  12.      this.accountDataArray = result
  13.      console.log("test,获取数据成功:", JSON.stringify(this.accountDataArray))
  14.    })
  15.   }
  16.  // 点击确定回调
  17.  onConfirm(insertData: AccountData) {
  18.    console.log("test", JSON.stringify(insertData))
  19.    // 插入数据
  20.    this.dbUitls.insertData(insertData, (res: number) => {
  21.      if (res > 0) {
  22.        // AlertDialog.show({ message: "添加成功" })
  23.        this.queryData()
  24.      } else {
  25.        AlertDialog.show({ message: "添加失败" })
  26.      }
  27.    })
  28.   }
复制代码
 
4. 组件&布局

1.用过flex布局吗?flex存在的问题是什么?为什么会造成二次渲染?怎样优化?


2. flex导致二次布局的原因,以及调研的经历

flex中flexgrow=1时,子组件宽度和大于flex的宽度时,页面渲染后,会调整子组件宽度使之宽度和等于flex的宽度,造成二次布局渲染 ​ flex中flexshrink=1时,子组件宽度和小于flex的宽度时,页面渲染后,也会调整子组件宽度使之宽度和等于flex的宽度,造成二次布局渲染

 
3.使用了哪些组件,有没有写过自界说组件,自界说组件怎么设计的


 
4. 自界说组件,实际开发中封装过哪些自界说组件

例如:下拉刷新、自界说弹窗、自界说LoadingProgress、统一标题栏的封装等...
自界说组件具有以下特点:

自界说组件基于struct实现,struct + 自界说组件名 + {...}的组合构成自界说组件,不能有继承关系。
struct被@Component装饰后具备组件化的本领,需要实现build方法形貌UI,一个struct只能被一个@Component装饰。
5.项目中用到arkTs哪些技能

arkTs的技能?
装饰器
渲染控制:

 
6.flex-shrink的使用

答: 设置父容器压缩尺寸分配给此属性所在组件的比例, 设置为==0表示不压缩==, 父容器为Row、Column时,默认值:0。 父容器为flex时,默认值:1。 在子组件的总宽度大于父容器的宽度时,子组件中有设置flex-shrink , 并且值大于0时,父容器会把剩余宽度按照比例压缩子组件。

Flex布局-通用属性-组件通用信息-组件参考(基于ArkTS的声明式开发范式)-ArkTS API参考-HarmonyOS应用开发
关于flexShrink怎样计算

参考:flex-shrink的计算方法 - 简书
分析过程:

自己总结公式:
溢出值:所有子元素宽度相加 - 父元素宽度
总权重:子元素1的flexShrink*子元素1宽度 + 子元素2的flexShrink*子元素2宽度 +...
子元素压缩值:溢出值 * 子元素的权重 = 溢出值 * 子元素1的flexShrink*子元素1宽度/总权重
 
7.webview组件怎样使用,ets文件怎样与h5通讯 ***

   总结:两种方式:
  方式一:本题
  runJavaScript() arkts-》H5 ​ javaScriptProxy() 和 registerjavaScriptProxy() H5-》arkts
  方式二:下一题
  createWebMessagePorts postMessage onMessageEvent 数据通道
   
  这里的方案是,相互调用函数来通讯,12题是通过消息端口建立数据通道
   8.webview怎样拿到外面的数据,怎样跟外部通讯 ***

可以通过WebView的WebMessagePort来进行通讯,详细通讯流程图如下:

完备代码,参考官网:文档中心
然后找到postMessage,查看完备示例代码(或找到InterviewQuestion项目中的WebComponent.ets)
 
==注意==:

 
 
==问题==: 模拟器中web加载网页后,网页的按钮无法点击。所以上述案例中,在模拟器中,是无法测试html端---应用端的数据传递。

==问题==: 在将端口0发送到html端时,使用的方法是postMessage,而真正发送数据是通过postMessageEvent,区别在哪?



 
 
二. 网络请求&线程相关

 
1. 数据通讯 ***

eventHub : 普通事件发布,订阅

emitter : 处置惩罚进程内,线程间事件 , 发送事件会放到事件队列 ,多hap通讯方案

worker: 处置惩罚线程间事件,主要处置惩罚耗时势件

2、项目中接口请求的数据,需要进行缓存吗?鸿蒙化处置惩罚过程

根据自己项目中的业务逻辑形貌,MapKit需要将当前屏幕中展示的6个瓦片数据图片缓存到沙盒中, ​ 杀掉进程后,断开网络,打开app会展示缓存的数据瓦片。
2.promise怎样办理异步并发(Promise并发控制的实现方式)

异步并发涉及同时执行多个异步操纵。可以使用 Promise.all 或 Promise.allSettled 方法来处置惩罚多个异步操纵的并发执行。

 
参考链接:Promise异步并发控制Promise 异步并发控制-JavaScript中文网-JavaScript教程资源分享流派
3.异步提交,代码封装 (Promise怎样使用,有几种是否用方式,分别是什么)***

 
 
异步提交(例如异步请求提交数据),可以封装一个函数来处置惩罚异步操纵,使用 Promise 或者 async/await 提供异步编程的支持。

 
参考链接:
 
15.请先容一下Async await ,await是否阻塞线程?

async/await 是 JavaScript 中处置惩罚异步代码的一种方式,它建立在 Promise 根本之上,提供了更清晰和易读的语法。使用 await 关键字可以暂停异步函数的执行,等待 Promise 对象的办理(resolve)。
await 并不会阻塞整个线程。当碰到 await 时,它会让出线程的执行,使得其他任务可以继承执行。在背后,await 会暂停当前函数的执行,等待 Promise 对象的状态发生变化。
 
参考链接:async/await详解async、await详解_async await-CSDN博客
 
 
1. 鸿蒙系统http在接口请求时,系统自己应该是开启子线程来请求,那么为什么在项目中还要使用taskpool开辟子线程呢

鸿蒙底层的http请求实现是在子线程中进行的,但针对于请求参数的编码与返回值的剖析,这部分需要耗费时间来处置惩罚的业务逻辑,还是建议使用taskpool开辟子线程来处置惩罚
参考答案二:
鸿蒙底层的http请求实现是在子线程中进行的。但在http在接口请求时,我们再开辟的子线程主要用于单次任务的执行,并对于请求返回值的剖析,由于在返回大量时值剖析是比较耗费费时间的; 在多任务请求时TaskPool开辟的子线程可以执行麋集型任务的开发,更加的灵活方便,
2. http数据请求采取什么方案? 请求参数范例是怎么设计的,如果是object, Object与object有啥区别?

已融入ppt: 进阶day01: 61
在进行网络请求前,您需要在module.json5文件中申明网络访问权限。由于HarmonyOS提供了一种访问控制机制即应用权限,用来保证这些数据或功能不会被不当或恶意使用。
  1. {
  2.    "module" : {
  3.        "requestPermissions":[
  4.           {
  5.             "name": "ohos.permission.INTERNET"
  6.           }
  7.        ]
  8.    }
  9. }
复制代码
请求参数通常以键值对的情势进行传递,此中参数范例可以是字符串、数字等根本范例。如果涉及到发送复杂的数据结构,比如JSON对象,那么请求参数的范例大概是一个对象(Object)。
Object:通常指的是 ArkTS 中的内置对象范例,用于表示键值对集合。
object:通常指的是 ArkTS 中的对象范例。在 ArkTS 中,对象是一种复合数据范例,它可以包含多个键值对。对象可以是根本范例的包装对象,也可以是用户自界说的对象。
 
参考链接:
 
3. 都说服务端相应整个流程慢,到底慢在哪里

服务端相应整个流程慢大概有多个原因,这需要进行系统性的性能分析以确定根本原因。以下是一些大概导致服务端相应慢的常见原因:
为了准确定位服务端相应慢的原因,可以使用性能分析工具、日志分析工具以及监控工具进行详细的诊断。系统性的性能测试和监控可以帮助发现瓶颈,从而采取相应的优化策略。
 
参考链接:
 
4. 服务端相应期间会不会卡页面渲染

HarmonyOS(鸿蒙)是一个分布式操纵系统,与传统的 Web 开发有所不同。在 Web 开发中,服务端相应慢大概会导致页面在浏览器中渲染时出现卡顿,由于浏览器通常会在主线程上执行 JavaScript 代码,包罗处置惩罚相应数据和更新 DOM。
对于 HarmonyOS,服务端相应慢不会直接导致页面渲染的卡顿,由于 HarmonyOS 应用通常是本地应用,而不是在浏览器中运行的 Web 应用。HarmonyOS 应用的渲染通常是在本地设备上进行的,与服务端相应的速度关系不大。
但是,在 HarmonyOS 应用中,如果你的应用在进行网络请求时阻塞了主线程,例如在主线程上进行了同步的网络请求,那么这大概会导致 UI 的卡顿。因此,建议在进行网络请求时使用异步的方式,以制止阻塞主线程。
总体而言,HarmonyOS 应用的相应速度主要与本地设备的性能和网络请求的优化有关,与服务端相应慢是否会卡页面渲染关系较小。在应用开发中,建议合理使用异步操纵、优化网络请求和合理设计本地业务逻辑,以提供更好的用户体验。
 
参考链接:
 
5. 网络请求怎么使用 (你的项目中的网络请求用的是哪个api)***


 
起首需要请求相应的权限。

 
参考链接:文档中心
 
6. 联系人中涉及到哪些数据请求,畅连caas接口提供方

联系人(contact)提供了联系人管理本领,包罗添加联系人、删除联系人、更新联系人等。
HarmonyOS 提供了本领开发框架,你可以通过调用系统本领来获取联系人信息。如果联系人信息存储在设备本地,你大概需要使用数据存储和访问的 API 来获取这些信息。鸿蒙系统提供了分布式数据管理的本领,可以用于访问本地数据。 访问用户的敏感信息通常需要相应的权限。
关于 CaaS(Capability as a Service)接口提供方,鸿蒙系统提供了本领框架,使开发者可以调用系统本领。
 
参考链接:@ohos.contact(联系人)文档中心
 
7. axios请求参数怎样写范例

在Axios中,如果想指定请求参数的范例,可以通过设置HTTP头部来实现。发送JSON数据,可以设置Content-Type头部为application/json。
告诉服务器正在发送JSON格式的数据。data 对象会被自动转换为JSON字符串。
 
参考链接:axios请求参数范例及传参方式axios请求参数范例及传参方式_axios 请求参数是多个对象范例怎么传递-CSDN博客
 
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是在当火线程进行异步调用,可以制止阻塞主线程,保证步伐的相应速度,提高用户体验; ​
详细使用场景:
当需要执行I/O操纵时,使用异步操纵比使用线程+同步I/O操纵更合适。I/O操纵不但包罗了直接的文件、网络的读写,还包罗数据库操纵、Web Service、HttpRequest以及.Net Remoting等跨进程的调用。
当需要长时间CPU运算的场所,例如耗时较长的图形处置惩罚和算法执行时,建议使用子线程操纵。
 
参考二:
taskpool:是多线程异步,是通过调用线程池内的线程去异步完成任务;
promise:是同一个线程在各个任务间进行切换,通过临时挂起任务实现异步 ,异步代码会被挂起并在之后继承执行,并且同一时间只有一段代码执行。
10. 任务池(taskPool),worker,他们之间的区别及使用场景,实际项目怎么使用?

实现TaskPoolWorker内存模型线程隔断离,内存不共享。线程隔断离,内存不共享。参数传递机制采取标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。采取标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。支持ArrayBuffer转移和SharedArrayBuffer共享。参数传递直接传递,无需封装,默认进行transfer。消息对象唯一参数,需要自己封装。方法调用直接将方法传入调用。在Worker线程中进行消息剖析并调用对应方法。返回值异步调用后默认返回。主动发送消息,需在onmessage剖析赋值。生命周期TaskPool自行管理生命周期,无需关心任务负载高低。开发者自行管理Worker的数量及生命周期。任务池个数上限自动管理,无需配置。同个进程下,最多支持同时开启8个Worker线程。任务执行时长上限无穷制。无穷制。设置任务的优先级不支持。不支持。执行任务的取消支持取消任务队列中等待的任务。不支持。  
TaskPool中超长任务(大于3分钟)会被系统自动采取,怎样制止超长任务?

将超大数据进行分段处置惩罚
CPU麋集型任务开发指导-使用多线程并发本领进行开发-并发-ArkTS语言根本类库-开发-HarmonyOS应用开发
 
补充:
Worker:Worker中不能直接更新Page。Worker是否配置文件:在工程的模块级build-profile.json5文件的buildOption属性中添加配置信息。
taskPool与worker参数传递中数据范例支持:
根本范例数据、传递通过自界说class创建出来的object时,不会发生序列化错误
@ohos.worker (启动一个Worker)-语言根本类库-ArkTS接口参考-ArkTS API参考-HarmonyOS应用开发
 
常见的一些开发场景及适用详细分析如下:
11. 异步方法Promise,callback,promise是在哪个线程? 是否会卡主线程?实际开发中会优先使用哪种方式做回调?await是否会卡线程?

答:
Promise是在主线程执行的,不会卡主线程,是一种异步编程方式,用于处置惩罚异步操纵。
await 不会卡线程,await 关键字会暂停当前异步函数的执行,并将控制权交还给事件循环,直到promise对象剖析或拒绝。
通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的剖析(完成或拒绝),以同步的方式编写异步操纵的代码。
优先使用promise。
 
12.promise怎样使用?会不会阻塞UI线程(可了解下底层实现逻辑)

Promise 是 JavaScript 中用于处置惩罚异步操纵的一种机制,它提供了更优雅的方式来处置惩罚异步代码,制止了回调地狱 。
Promise不会阻塞UI线程,Promise设计的目标之一就是制止阻塞主线程。异步操纵的执行不会阻塞 UI 线程,而是通过事件循环机制在后台执行。当异步操纵完成后,它会调用相应的 resolve 或 reject,然后触发注册的 then 或 catch 处置惩罚步伐。
 
 
16. 子线程和主线程的消息传递

Worker开辟的子线程需要配合postMessage和onMessage实现消息传递;
TaskPool开辟的子线程通过回调传递进行传递;对连续订阅事件或单次订阅事件的处置惩罚、取消订阅事件、发送事件到事件队列等是通过Emitter发送和处置惩罚事件的。
 

 
17. 主线程上的数据对象序列化后传到子线程,子线程改变了对象的属性值,主线程跟着一起改变吗

不会,序列化是转换为字节码,已经和之前的对象没有关系了,就算反序列化成对象也是一个新对象。

 
18. then调用和await调用的区别

已融入ppt: 进阶day02-21
当使用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是否答应修饰在生命周期方法前

语法不报错,但是不建议添加,大概会引起阻塞
 
 
三. 性能&优化

1. 页面性能内存优化***?

性能和内存是两个指标,偶尔候追求性能,就需要做缓存处置惩罚,吃内存。
页面内存优化,主要在减少缓存的处置惩罚。
 
页面性能优化,主要在少嵌套,减少动态渲染的频率。


 
17.arkTs语言高性能写法有哪些


 
6. 页面布局上的性能和内存上的注意事项

 
1、使用row/column+layoutweight代替flex容器使用 2、scroll嵌套list/grid容器时,要设置容器的宽高,数组数据渲染尽量使用lazyforeach渲染item 3、组件的显隐设置,要使用if语句来判断,制止使用visibility 4、list/grid容器要根据详细场景来使用cachecount,制止卡顿
 
 
1.使用row/column代替flex容器使用

  1. @Entry
  2. @Component
  3. struct MyComponent {
  4.  build() {
  5.    Flex({ direction: FlexDirection.Column }) {
  6.      Flex().width(300).height(200).backgroundColor(Color.Pink)
  7.      Flex().width(300).height(200).backgroundColor(Color.Yellow)
  8.      Flex().width(300).height(200).backgroundColor(Color.Grey)
  9.    }
  10.   }
  11. }
复制代码

  1. @Entry
  2. @Component
  3. struct MyComponent {
  4.  build() {
  5.    Column() {
  6.      Row().width(300).height(200).backgroundColor(Color.Pink)
  7.      Row().width(300).height(200).backgroundColor(Color.Yellow)
  8.      Row().width(300).height(200).backgroundColor(Color.Grey)
  9.    }
  10.   }
  11. }
复制代码

2. 使用row/column代替flex容器使用

  1. class BasicDataSource implements IDataSource {
  2.  private listeners: DataChangeListener[] = []
  3.  public totalCount(): number {
  4.    return 0
  5.   }
  6.  public getData(index: number): number {
  7.    return index
  8.   }
  9.  registerDataChangeListener(listener: DataChangeListener): void {
  10.    if (this.listeners.indexOf(listener) < 0) {
  11.      console.info('add listener')
  12.      this.listeners.push(listener)
  13.    }
  14.   }
  15.  unregisterDataChangeListener(listener: DataChangeListener): void {
  16.    const pos = this.listeners.indexOf(listener);
  17.    if (pos >= 0) {
  18.      console.info('remove listener')
  19.      this.listeners.splice(pos, 1)
  20.    }
  21.   }
  22.  notifyDataReload(): void {
  23.    this.listeners.forEach(listener => {
  24.      listener.onDataReloaded()
  25.    })
  26.   }
  27.  notifyDataAdd(index: number): void {
  28.    this.listeners.forEach(listener => {
  29.      listener.onDataAdd(index)
  30.    })
  31.   }
  32.  notifyDataChange(index: number): void {
  33.    this.listeners.forEach(listener => {
  34.      listener.onDataChange(index)
  35.    })
  36.   }
  37.  notifyDataDelete(index: number): void {
  38.    this.listeners.forEach(listener => {
  39.      listener.onDataDelete(index)
  40.    })
  41.   }
  42.  notifyDataMove(from: number, to: number): void {
  43.    this.listeners.forEach(listener => {
  44.      listener.onDataMove(from, to)
  45.    })
  46.   }
  47. }
  48. class MyDataSource extends BasicDataSource {
  49.  private dataArray: Array<string> = new Array(100).fill('test')
  50.  public totalCount(): number {
  51.    return this.dataArray.length
  52.   }
  53.  public getData(index: number): number {
  54.    return Number(this.dataArray[index])
  55.   }
  56.  public addData(index: number, data: string): void {
  57.    this.dataArray.splice(index, 0, data)
  58.    this.notifyDataAdd(index)
  59.   }
  60.  public pushData(data: string): void {
  61.    this.dataArray.push(data)
  62.    this.notifyDataAdd(this.dataArray.length - 1)
  63.   }
  64. }
  65. @Entry
  66. @Component
  67. struct MyComponent {
  68.  private data: MyDataSource = new MyDataSource()
  69.  build() {
  70.    Scroll() {
  71.      List() {
  72.        LazyForEach(this.data, (item: string, index?: number|undefined) => {
  73.          ListItem() {
  74.            if(index){
  75.              Text('item value: ' + item + (index + 1)).fontSize(20).margin(10)
  76.            }
  77.          }.width('100%')
  78.        })
  79.      }.width('100%').height(500)
  80.    }.backgroundColor(Color.Pink)
  81.   }
  82. }
复制代码
 
3. 组件的显隐设置,要使用if语句来判断,制止使用visibility


4. list/grid容器要根据详细场景来使用cachedcount,制止卡顿 (看官网的list组件有cachedcount的先容)

文档中心
7.页面性能优化

TODO:这个比及最佳实践处置惩罚完之后,完善


5.如果简历中有写相关性能优化得东西,形貌一下项目中是怎样做得


四. 其他:

1. hap,har和hsp有啥区别***,自己平常是怎么打包的?有没有单独编写脚本打包?

har和hsp区别?只有体积巨细的区别吗? 办理体积膨胀的问题,har是安装包直接安装在进程里
 

2. 三方应用调用系统应用,对于ability的交互和传值有什么限制?除了数据巨细方面

重点先容自己对ability的明白,形貌显式want和隐式want的区别,带入到对应口试项目中场景来 启动应用内的UIAbility 启动应用内的UIAbility并获取返回结果 启动其他应用的UIAbility 启动其他应用的UIAbility并获取返回结果 启动UIAbility的指定页面 显式Want启动:在want参数中需要设置该应用bundleName和abilityName,当需要拉起某个明确的UIAbility时,通常使用显式Want启动方式。 隐式Want启动:不明确指出要启动哪一个UIAbility,在调用startAbility()方法时,其入参want中指定了一系列的entities字段(表示目标UIAbility额外的类别信息,如浏览器、视频播放器)和actions字段(表示要执行的通用操纵,如查看、分享、应用详情等)等参数信息,然后由系统去分析want,并帮助找到合适的UIAbility来启动。
 
==三方应用调用系统应用== , 需要用到want , want分为显示和隐式

==关于传值== , 我之前做过授权的功能 , 如果用户第一次拒绝授权,第二次再次进去此页面,则可以直接引导用户调到应用设置界面



==对数据范例的限制==,目前支持的数据范例有:字符串、数字、布尔、对象、数组和文件形貌符等。
 
3. 项目中是否使用过泛型, 联合项目使用展开

4. 从先容中延伸出har和下沉到系统的so的优缺点

har分为静态分享库和动态分享库,静态分享库天生har包集成到应用中,应用运行时直接加载到进程中,动态分享库天生hsp和har包,har集成到应用中,hsp需要安装到手机设备中,应用运行时,har直接加载到进程中,但hsp需要业务调用才会加载; ​ so是c++和arkts的混编,arkts开发完成后,编译天生对应的js文件,使用华为工具将js文件和NAPI混编为so; ​ 目前api10和api11不支持har包下沉到系统称为预置SDK,仅支持so。
 
待完善
12、了解过鸿蒙的Napi吗?如果我需要编译三方库怎样链接? 组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架在HarmonyOS中, C API中的N-API接口可以实现ArkTS/TS/JS与C/C++之间的交互。N-API提供的接口名与三方Node.js同等,目前支持部分接口
10、鸿蒙怎样实现自界说Canvas?底层怎样进行Ui的渲染 flutter skia 11、Navigation组件和NavPathStack使用
 
 

8.Record 和 map 的区别

9.string array map 和 object 关系


 
 
14.踩坑文档有什么内容,印象最深的问题是啥

偶尔候官方文档不够详细。比如:
 
15.加密怎么实现的,怎样存储

关于数据库加密:键值型数据库和关系型数据库均支持数据库加密操纵,都是在创建数据库的时候通过options配置参数来开启加密。加密之后则无法通过其他方式打开数据库文件,只能通过接口访问。
关于数据加密:Samples: We provide a series of app samples to help you quickly get familiar with the APIs and app development process of the HarmonyOS SDKs. | 为帮助开发者快速认识HarmonyOS SDK所提供的API和应用开发流程,我们提供了一系列的应用示例 - Gitee.com

 
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4