初识arkts
什么是arkts
ArkTS是HarmonyOS优选的主力应用开发语言。
ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。
目前流行的编程语言TypeScript是在JavaScript基础上通过添加类型定义扩展而来的,而ArkTS则是TypeScript的进一步扩展。TypeScript深受开发者的喜爱,因为它提供了一种更结构化的JavaScript编码方法。ArkTS旨在保持TypeScript的大部分语法,为现有的TypeScript开发者实现无缝过渡,让移动开发者快速上手ArkTS。
arkts基本知识
声明
声明:
ArkTS通过声明引入变量、常量、函数和类型。
变量声明:
以关键字let开头的声明引入变量,该变量在程序执行期间可以具有不同的值。
常量声明:
以关键字const开头的声明引入只读常量,该常量只能被赋值一次。
对常量重新赋值会造成编译时错误。
//1.变量的声明
let str1:string='你好';
let str2='你好';//自动推导数据类型
// str2=123;//变量的数据类型,不能改变
// 不允许使用var声明
// var a=123;
// const 声明的是常量,只能赋值一次
const str3:string='123';
// str3='234';
自动类型推断
自动类型推断
由于ArkTS是一种静态类型语言,所有数据的类型都必须在编译时确定。
但是,如果一个变量或常量的声明包含了初始值,那么开发者就不需要显式指定其类型。ArkTS规范中列举了所有允许自动推断类型的场景。
以下示例中,两条声明语句都是有效的,两个变量都是string类型:
类型
数字类型
Number
ArkTS提供number和Number类型,任何整数和浮点数都可以被赋给此类型的变量。
数字字面量包括整数字面量和十进制浮点数字面量。
//数据类型
//1.number
let num1:number=123;//10进制
let num2:number=0b1;//2进制
let num3:number=0o17;//8进制
let num4:number=0xfac;//16进制
布尔类型(Boolean)
Boolean类型
boolean类型由true和false两个逻辑值组成。
通常在条件语句中使用boolean类型的变量
let isDone: boolean = false;
//...
if (isDone){
console.log('Done!')
}
字符串类型
tring类型
string代表字符序列;可以使用转义字符来表示字符。
字符串字面量由单引号(')或双引号(")之间括起来的零个或多个字符组成。字符串字面量还有一特殊形式,是用反向单引号(`)括起来的模板字面量。
// 字符串
let str5:string='hello word';
let str6:string="hello word";
let str7:string=`hello word${num1}`;
void类型
void类型用于指定函数没有返回值。
此类型只有一个值,同样是void。由于void是引用类型,因此它可以用于泛型类型参数。
// void
class Class<T>{
// ...
}
let instance: Class <void>
Object类型
Object类型是所有引用类型的基类型。任何值,包括基本类型的值(它们会被自动装箱),都可以直接被赋给Object类型的变量。
//Object 是所有类型的基础类
let ob:Object=123;
Array类型
array,即数组,是由可赋值给数组声明中指定的元素类型的数据组成的对象。
数组可由数组复合字面量(即用方括号括起来的零个或多个表达式的列表,其中每个表达式为数组中的一个元素)来赋值。数组的长度由数组中元素的个数来确定。数组中第一个元素的索引为0。
// Array
let names: string[]=['asd','sdf','dfg'];
Enum类型
enum类型,又称枚举类型,是预先定义的一组命名值的值类型,其中命名值又称为枚举常量。
使用枚举常量时必须以枚举类型名称为前缀。
//枚举
enum Sex{
男,女
}
let sex1:Sex=Sex.女;
let sex2:Sex=1;
Union类型
union类型,即联合类型,是由多个类型组合成的引用类型。联合类型包含了变量可能的所有类型。
可以用不同的机制获取联合类型中特定类型的值。
class Dog{
play(){
console.log('狗')
}
}
class Cat{
play(){
console.log('猫')
}
}
class Penguin{
play(){
console.log('企鹅')
}
}
// Pet 是联合类型
type Pet=Dog|Cat|Penguin
let p1:Pet=new Dog();
p1.play()
Aliases类型
Aliases类型为匿名类型(数组、函数、对象字面量或联合类型)提供名称,或为已有类型提供替代名称。
运算符
赋值运算符
赋值运算符=,使用方式如x=y。
复合赋值运算符将赋值与运算符组合在一起,其中x op = y等于x = x op y。
复合赋值运算符列举如下:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=。
比较运算符
算术运算符
位运算符
逻辑运算符
语句
if语句
if语句用于需要根据逻辑条件执行不同语句的场景。当逻辑条件为真时,执行对应的一组语句,否则执行另一组语句(如果有的话)。
else部分也可能包含if语句。
条件表达式可以是任何类型。但是对于boolean以外的类型,会进行隐式类型转换:
Switch语句
使用switch语句来执行与switch表达式值匹配的代码块。
如果switch表达式的值等于某个label的值,则执行相应的语句。
如果没有任何一个label值与表达式值相匹配,并且switch具有default子句,那么程序会执行default子句对应的代码块。
break语句(可选的)允许跳出switch语句并继续执行switch语句之后的语句。
如果没有break语句,则执行switch中的下一个label对应的代码块。
条件表达式
条件表达式由第一个表达式的布尔值来决定返回其它两个表达式中的哪一个。
condition ? expression1 : expression2
如果condition的为真值(转换后为true的值),则使用expression1作为该表达式的结果;否则,使用expression2。
for语句
for语句会被重复执行,直到循环退出语句值为false。
for语句的执行流程如下:
1、 执行init表达式(如有)。此表达式通常初始化一个或多个循环计数器。
2、 计算condition。如果它为真值(转换后为true的值),则执行循环主体的语句。如果它为假值(转换后为false的值),则for循环终止。
3、 执行循环主体的语句。
4、 如果有update表达式,则执行该表达式。
5、 回到步骤2。
For-of语句
使用for-of语句可遍历数组或字符串。示例如下:
for (forVar of expression) {
statements
}
While,Do-while语句
只要condition为真值(转换后为true的值),while语句就会执行statements语句
let n=0;
let x=0;
while(n<3){
n++;
x += n;
}
如果condition的值为真值(转换后为true的值),那么statements语句会重复执行。
let i=0;
do{
i+=1;
} while (i<10)
Break语句,Continue语句
Break语句
使用break语句可以终止循环语句或switch。
如果break语句后带有标识符,则将控制流转移到该标识符所包含的语句块之外。
Continue语句
continue语句会停止当前循环迭代的执行,并将控制传递给下一个迭代。
Throw和Try语句
throw语句用于抛出异常或错误
try语句用于捕获和处理异常或错误
function tryCatch(){
let aaa:number=0;
try {//有可能出现问题的代码
aaa=Err.add(1,0)
}catch (e){//出现问题后的解决办法 e--->错误信息
console.log(e)
Err.add(1,1)
} finally {//异常的最终处理方案
// 不管代码有没有出现异常都会执行
return aaa;
}
}
函数
函数声明
函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体。
以下示例是一个简单的函数,包含两个string类型的参数,返回类型为string:
function add(x:string,y:string):string{
let z:string = `${x} ${y}`
return z
}
可选参数
可选参数的格式可为name?: Type。
可选参数的另一种形式为设置的参数默认值。如果在函数调用中这个参数被省略了,则会使用此参数的默认值作为实参。
// 可选参数要放在最后
function getAge(name?:string,sex?:string){
if(name){
return `${name} ${sex}`
}
return `无名${sex}`
}
// b默认值是3
function add(a:number,b:number=3){
return a+b;
}
let a1=add(2,6)
let a22=add(2)
Rest参数
函数的最后一个参数可以是rest参数。使用rest参数时,允许函数或方法接受任意数量的实参。
//rest参数 不确定数量的参数
function ages(name:string,...ages:number[]){
console.log(`${name}班有${ages.length}`)
let sum=0
for (let el of ages){
sum+=el
}
console.log(`年龄总和:${sum},平均值${sum/ages.length}`)
return sum/ages.length
}
let avgAge= ages('鸿蒙',12,23,18,21,17,19)
返回类型
如果可以从函数体内推断出函数返回类型,则可在函数声明中省略标注返回类型
// 显示指定返回类型
function foo():string {return 'foo'}
// 推断返回类型为string
function goo() {return 'goo'}
不需要返回值的函数的返回类型可以显式指定为void或省略标注。这类函数不需要返回语句。
function hi1() {console.log('hi')}
function hi2():void {console.log('hi')}
函数的作用域
函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。
如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。
函数调用
调用函数以执行其函数体,实参值会赋值给函数的形参。
function join(x:string,y:string):string{
let z:string = `${x} ${y}`
return z
}
let x1=join('hello','word')
console.log(x1)
函数类型
函数类型通常用于定义回调:
let lam3=(x:number)=>number //这是一个函数类型
function lam(f:lam3){
f(3.1415926) //调用函数
}
lam(Math.sin) //将函数作为参数传入
箭头函数(又名Lambda函数)
函数可以定义为箭头函数,例如:
function lam(x:number,y:number):number=>{
return x+y
}
箭头函数的返回类型可以省略;省略时,返回类型通过函数体推断。
表达式可以指定为箭头函数,使表达更简短,因此以下两种表达方式是等价的:
let lam2=(x:number,y:number)=>{x+y}
let lam3=(x:number,y:number)=>x+y
闭包
闭包是由函数及声明该函数的环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。
在下例中,f函数返回了一个闭包,它捕获了count变量,每次调用z,count的值会被保留并递增。
function abc5():()=>number{
let a=0;
let g=():number=>{a++; return a}
return g;
}
let abc6=abc5()
abc6() //返回1
abc6() //返回2
类
类声明引入一个新类型,并定义其字段、方法和构造函数。
定义类后,可以使用关键字new创建实例
可以使用对象字面量创建实例
在以下示例中,定义了Person类,该类具有字段name和构造函数和方法fullName
//创建对象
export class Person{
// 属性 必须要给初始值
firstName:string=''
lastName:string=''
// 构造函数:给属性初始值,初始化属性
// constructor() {
// console.log('无参函数')
// }
constructor(firstName:string,lastName:string) {
this.firstName=firstName
this.lastName=lastName
}
fullName(){
return this.lastName+this.firstName
}
}
let p:Person=new Person('z','s')
// 实例字段,通过new对象之后访问的字段
p.firstName='啧啧啧';
class Person2{
firstName:string=''
lastName:string=''
// 字面量创建对象不能有构造函数/函数
}
//字面量创建对象
let pp:Person2={firstName:'三',lastName:'张'}
字段
字段是直接在类中声明的某种类型的变量。
类可以具有实例字段或者静态字段。
实例字段
实例字段存在于类的每个实例上。每个实例都有自己的实例字段集合。
要访问实例字段,需要使用类的实例
字段初始化
ArkTS要求所有字段在声明时或者构造函数中显式初始化。这和标准TS中的strictPropertyInitialization模式一样。
export class Person{
// 属性 必须要给初始值
firstName:string=''
lastName:string=''
constructor(firstName:string,lastName:string) {
this.firstName=firstName
this.lastName=lastName
}
fullName(){
return this.lastName+this.firstName
}
}
let p:Person=new Person('z','s')
// 实例字段,通过new对象之后访问的字段
p.firstName='啧啧啧';
静态字段
使用关键字static将字段声明为静态。静态字段属于类本身,类的所有实例共享一个静态字段。
静态字段需要使用类名进行访问
方法
方法属于类。类可以定义实例方法或者静态方法。静态方法属于类本身,只能访问静态字段。而实例方法既可以访问静态字段,也可以访问实例字段,包括类的私有字段。
静态方法
用关键字static将方法声明为静态。静态方法属于类本身,只能访问静态字段。
静态方法定义了类作为一个整体的公共行为。
必须通过类名调用静态方法
export class Person3{
// 静态字段
static firstName:string=''
lastName:string=''
a2(){
}
a3(){
this.a2()
}
//静态函数
static a(num1:number,num2:number){
Person3.firstName='张三'
// 不支持this,无法直接访问非静态字段/函数
// this.lastName='aa'
// a2()
return num1+num2
}
}
// 静态字段使用类名进行访问
Person3.firstName='ss'
// let p3=new Person3();
// p3.a(1,2)
继承
一个类可以继承另一个类(称为基类),并使用以下语法实现多个接口
继承类继承基类的字段和方法,但不继承构造函数。继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。
基类也称为“父类”或“超类”。继承类也称为“派生类”或“子类”。
包含implements子句的类必须
实现列出的接口中定义的所有方法,
但使用默认实现定义的方法除外
父类访问
关键字super可用于访问父类的实例字段、实例方法和构造函数。在实现子类功能时,可以通过该关键字从父类中获取所需接口
方法的重写与重载
子类可以重写其父类中定义的方法的实现。重写的方法必须具有与原始方法相同的参数类型和相同或派生的返回类型。
通过重载签名,指定方法的不同调用。具体方法为,为同一个方法写入多个同名但签名不同的方法头,方法实现紧随其后,如果两个重载签名的名称和参数列表均相同,则为错误
// 宠物 父类,基类,超类
class Pet{
name:string=''
sex:string=''
static age:number=0
constructor(name:string,sex:string) {
this.name=name
this.sex=sex
}
show(){
return `昵称:${this.name},性别:${this.sex}`
}
}
//子类 只支持单继承
class Dog extends Pet{
// 必须调用父类的有参的构造函数
constructor(name:string,sex:string) {
// super调用父类的构造函数
super(name,sex)
}
type:string=''
// 重写:子类重写父类的函数
// 1.方法名相同 2.参数类型相同 3.返回值类型相同,或是其子类
show(){
return super.show()+'品种'+this.type
}
a(){
this.show()//子类
super.show()//父类
}
// 重载:1.同一个类中,方法名相同,参数列表不同,返回值类型相同
// shows(a:number){
// }
// shows(){
// }
}
let pe=new Pet('zs','公')
// 子类函数和父类函数重名,会调用子类函数
pe.show()
但在Arkts中不建议使用方法的重载,比如下列重载代码的重复
class Over{
// 重载
aa(x:number):void
aa(x:string):void
aa(x:number|string):void{}
}
构造函数
类声明可以包含用于初始化对象状态的构造函数
如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数
在这种情况下,默认构造函数使用字段类型的默认值来初始化实例中的字段
class Pet{
name:string=''
sex:string=''
static age:number=0
constructor(name:string,sex:string) {
this.name=name
this.sex=sex
}
show(){
return `昵称:${this.name},性别:${this.sex}`
}
}
派生类的构造函数
构造函数函数体的第一条语句可以使用关键字super来显式调用直接父类的构造函数。
constructor(name:string,sex:string) {
super(name,sex)
}
可见性修饰符
类的方法和属性都可以使用可见性修饰符。
- Public(公有)
public修饰的类成员(字段、方法、构造函数)在程序的任何可访问该类的地方都是可见的。 - Private(私有)
private修饰的成员不能在声明该成员的类之外访问 - Protected(受保护)
protected修饰符的作用与private修饰符非常相似,不同点是protected修饰的成员允许在派生类中访问 - getter和setter
setter和getter可用于提供对对象属性的受控访问
class Aa{
// 共有的
public a1:string=''
// 受保护的:本类和子类中使用
protected a2:string=''
// 私有的
private a3:string=''
}
let aa=new Aa();
class Bb extends Aa{
show(){
this.a2='asd'
}
}
let bb=new Bb();
// getter/setter
class Pri{
private _a1: string
public set a1(value: string) {
this._a1 = value
}
public get a1(): string {
return this._a1
}
private _a2: string
public set a2(value: string) {
this._a2 = value
}
public get a2(): string {
return this._a2
}
constructor(a1:string,a2:string) {
this._a1=a1
this._a2=a2
}
对象字面量
对象字面量是一个表达式,可用于创建类实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式。
对象字面量的表示方式是:封闭在花括号对({})中的’属性名:值’的列表
对象字面量只能在可以推导出该字面量类型的上下文中使用
也可以在数组元素类型或类字段类型中使用
class Pri{
private _a1: string
public set a1(value: string) {
this._a1 = value
}
public get a1(): string {
return this._a1
}
private _a2: string
public set a2(value: string) {
this._a2 = value
}
public get a2(): string {
return this._a2
}
constructor(a1:string,a2:string) {
this._a1=a1
this._a2=a2
}
}
let p1=new Pri('1','2');
p1.a1
Record类型的对象字面量
泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)。常用对象字面量来初始化该类型的值
类型K可以是字符串类型或数值类型,而V可以是任何类型
class Stu{
name:string=''
age:number=0
}
let map2:Record<string,Stu>={
'张三':{name:'张三',age:18},
'张2':{name:'张2',age:18},
'张4':{name:'张4',age:18},
'张5':{name:'张5',age:18},
'张6':{name:'张6',age:18}
}
let s:Stu=map2['张三'];
接口
接口
接口声明引入新类型。接口是定义代码协定的常见方式。
任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态。
接口通常包含属性和方法的声明
//接口
interface Stus{
// 接口中的方法,没有方法体(方法的实现)
eat():void
study():number
}
//(实现类) 实现接口,必须重写接口中的方法
class Stu1 implements Stus{
eat(): void {
console.log('学生在吃')
}
study(): number {
console.log('学生在学习')
return 100
}
}
接口属性
接口属性可以是字段、getter、setter或getter和setter组合的形式。
属性字段只是getter/setter对的便捷写法
实现接口的类也可以使用以下两种方式
interface Stu2{
// 接口的属性会在实现类中默认隐式生成getter/setter方法
name:string
sex:string
eat():void
study():number
}
class Stu3 implements Stu2{
name: string=''
sex: string=''
eat(): void {
throw new Error('Method not implemented.')
}
study(): number {
throw new Error('Method not implemented.')
}
}
let stu3=new Stu3();
stu3.name='123'
接口继承
接口可以继承其他接口,如下面的示例所示
interface Inte1{
a():void
}
interface Inte2 extends Inte1{
b():void
}
class Imp1 implements Inte2{
b(): void {
throw new Error('Method not implemented.')
}
a(): void {
throw new Error('Method not implemented.')
}
}
继承接口包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。
继承关键字extends
泛型
泛型类型和函数
泛型类型和函数允许创建的代码在各种类型上运行,而不仅支持单一类型。
泛型类和接口
类和接口可以定义为泛型,将参数添加到类型定义中,如以下示例中的类型参数Element:
//泛型 T类,K:key V:value E:element集合 ?不确定
// N:number
class Fx<E>{
a(e:E):void{}
}
let fx=new Fx<number[]>()
fx.a([1,2])
// 返回数字数组的最后一个元素
function lastGet(x:number[]):number{
return x[x.length-1]
}
let aa=lastGet([1,2,3,4])
//返回任意类型数组的最后一个元素
function getLast<T>(x:T[]):T{
return x[x.length-1]
}
let a2=getLast<string>(['1','2','3'])
空安全
默认情况下,ArkTS中的所有类型都是不可为空的,因此类型的值不能为空。这类似于TypeScript的严格空值检查模式(strictNullChecks),但规则更严格。
非空断言运算符
后缀运算符!可用于断言其操作数为非空。
应用于可空类型的值时,它的编译时类型变为非空类型。例如,类型将从T | null更改为T:
// 非空断言
export class A{
a:number=0
}
空值合并运算符
空值合并二元运算符??用于检查左侧表达式的求值是否等于null或者undefined。如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式。
换句话说,a ?? b等价于三元运算符(a != null && a != undefined) ? a : b。
//空值合并运算符
export function hb(str:string|null){
// return (str!=null && str!=undefined)?str:'asd'
return str ?? 'asd'
}
可选链
在访问对象属性时,如果该属性是undefined或者null,可选链运算符会返回undefined。
说明:getSpouseNick的返回类型必须为string | null | undefined,因为该方法可能返回null或者undefined。
export function fc(aa:A|null){
// aa?.a=9
console.log(`${aa?.a}`)//可选链
// console.log(`${aa!.a}`)
}
并发
并发是指在同一时间内,存在多个任务同时执行的情况。对于多核设备,这些任务可能同时在不同CPU上并行执行。对于单核设备,多个并发任务不会在同一时刻并行执行,但是CPU会在某个任务休眠或进行I/O操作等状态下切换任务,调度执行其他任务,提升CPU的资源利用率。
异步并发 (Promise和async/await)
Promise和async/await提供异步并发能力,是标准的JS异步语法。异步代码会被挂起并在之后继续执行,同一时间只有一段代码执行,适用于单次I/O任务的场景开发,例如一次网络请求、一次文件读写等操作。无需另外启动线程执行。
异步语法是一种编程语言的特性,允许程序在执行某些操作时不必等待其完成,而是可以继续执行其他操作。
console.log('任务1');
setTimeout(() => {
console.log('任务2');
}, 2000);
console.log('任务3');
console.log('任务4');
console.log('任务5');
console.log('任务6');
回调地狱
回调地狱的概念:回调函数里面嵌套回调函数。
回调地狱是为了让我们代码执行顺序的一种操作(解决异步),但是它会使我们的可读性非常差。
// 生成10个随机数,每隔一秒生成一个 回调地狱
setTimeout(() => {
console.log(Math.random()+'');
setTimeout(() => {
console.log(Math.random()+'');
}, 1000);
}, 1000);
Promise
Promise是一种用于处理异步操作的对象,可以将异步操作转换为类似于同步操作的风格,以方便代码编写和维护。Promise提供了一个状态机制来管理异步操作的不同阶段,并提供了一些方法来注册回调函数以处理异步操作的成功或失败的结果。
Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已拒绝)。Promise对象创建后处于pending状态,并在异步操作完成后转换为fulfilled或rejected状态。
最基本的用法是通过构造函数实例化一个Promise对象,同时传入一个带有两个参数的函数,通常称为executor函数。executor函数接收两个参数:resolve和reject,分别表示异步操作成功和失败时的回调函数
// resolve 成功 reject 失败
let p1=new Promise((resolve,reject)=>{
// 生成随机数,小于0.5失败,大于0.5成功
let num=Math.random()
if(num<0.5){
reject('小于0.5')
}else{
resolve('成功:'+num)
}
});
then方法和catch方法
Promise对象创建后,可以使用then方法和catch方法指定fulfilled状态和rejected状态的回调函数。then方法可接受两个参数,一个处理fulfilled状态的函数,另一个处理rejected状态的函数。只传一个参数则表示当Promise对象状态变为fulfilled时,then方法会自动调用这个回调函数,并将Promise对象的结果作为参数传递给它。使用catch方法注册一个回调函数,用于处理“失败”的结果,即捕获Promise的状态改变为rejected状态或操作失败抛出的异常。
// 生成10个随机数,每隔一秒生成一个
let p2=new Promise((r,j)=>{
setTimeout(() => {
r(Math.random())
}, 1000);
})
p2
.then(data=>{
console.log(data);
// 下一个要执行的异步操作
return new Promise((r,j)=>{
setTimeout(() => {
r(Math.random())
}, 1000);
})
},
err=>{//处理失败
console.log(err);
}
)
.then(data=>{//接受的是上一个then的return的异步操作的结果
console.log(data);
})
.catch(err=>{
console.log(err);
})
async/await
async/await是一种用于处理异步操作的Promise语法糖,使得编写异步代码变得更加简单和易读。通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。
与then方法相比较async/await编写异步代码变得更加简单和易读
// async函数 达到的效果是同步代码的效果
// 1.生成一个promise
function p(){
return new Promise((r,j)=>{
setTimeout(() => {
let num=Math.random()
if(num>0.5){
r(num)
}else{
j(-1)
}
}, 1000);
})
}
// 使用异步函数
async function asy() {
console.log('开始执行异步操作');
try{
let num1=await p()
console.log(num1);
let num2=await p()
console.log(num2);
} catch(error){
console.log(error);
}
}
console.log('主线程任务开始');
asy()
注意
异步的写法在DevEco Studio中会有所不同
在编写异步的步骤中与上述中的区别在于
1.函数需要加上Promise数据类型,同时还需要加上返回值类型
2.在执行异步操作中,需要给打印语句转换成字符串类型
export function p():Promise<number>{
return new Promise((r,j)=>{
setTimeout(() => {
let num=Math.random()
if(num>0.5){
r(num)
}else{
j('你是个好人')
}
}, 1000);
})
}
export async function asy() {
console.log('开始执行异步操作');
try{
let num1=await p()
console.log(num1.toString());
let num2=await p()
console.log(num2.toString());
} catch(error){
console.log(error);
}
}