HarmonyOS开发5.0【Promise】

1 Promise是什么

1.1 基本概念

Promise 是用来管理异步操作的对象,可以获取成功(或失败)的结果

核心代码:

    const p = new Promise<string>((resolve, reject) => {
      // 执行任意代码,主要是异步
      // 成功 resolve(成功结果) then 执行
      // 失败 reject(失败结果) then第二个回调函数或 catch 执行
    })
    // 成功
    p.then(res => {})
    // 失败
    p.then(res => {}, (err: string) => {})
    p.then(res=>{}).catch((err:string)=>{})

1.2 作用

能够解决回调函数地狱(多层回调函数嵌套)

// 回调地狱写法
const req = http.createHttp()
req.request('接口1')
  .then(res1=>{
    req.request('接口2?p=接口1的结果res1')
      .then(res2=>{
        req.request('接口3?p=接口2的结果res2')
          .then(res3=>{
            req.request('接口4?p=接口3的结果res3')
              .then(res4=>{
                req.request('接口5?p=接口4的结果res4')
                  .then(res5=>{
                    req.request('接口6?p=接口5的结果res5')
                      .then(res6=>{

                      })
                  })
              })
          })
      })
  })

1.3 使用

核心三步走

  1. 内部执行异步代码
  2. 传递成功结果
  3. 传递失败结果
// 1.  内部执行异步代码
  const p = new Promise<string>((resolve,reject) => {
      // 执行任意代码,主要是异步
      setTimeout(() => {
        // 比如:获取随机数
        const randomNum = Math.floor(Math.random() * 100)
        // resolve(randomNum.toString())
        reject(randomNum.toString())
      },2000)
    })
// 2.  传递成功结果
    p.then(res => {
      console.log('res:', res)
    })
// 3.  传递失败结果
    .catch((err:string)=>{
      console.log('err:',err)
    })

2 Promise 的状态

Promise 必然处于 3 种状态中的某一种,调用resolve,reject 的本质就是更改他的状态

Promise的三种状态

  1. 待定(pending): 初始状态,既没有被兑现(resolve),也没有被拒绝(reject)
  2. 已兑现(fullfilled): 意味着操作成功完成
  3. 已拒绝(rejected): 意味着操作失败

1

注意事项:

状态的改变不可逆

调用 resolve 之后再调用 reject,状态还是 已兑现,反之亦然

拓展

直接得到一个成功或者失败的结果写法:

Promise.resolve(成功信息) //直接得到一个已兑现的Promise对象
Promise.reject(失败信息)  //直接得到一个已拒绝的Promise对象

3 链式编程

3.1 什么是链式编程

链式编程是在一个对象上可以重复点出方法,这些方法返回同一个类型的对象

2

特点

  1. 后面的 .then是可以接受到前面.then返回的成功状态下的值
  2. 后面的.catch是可以接受前面.then中返回的失败状态下的值
  3. 一旦在某个.then里面返回的是一个失败状态的Pormise,则直接跳过其他的.then进入到.catch执行

总结

写法: p.then().then()…catch() 注意点:如果 后一个.then需要用到前一个.then中的结果,需要在前一个.then中 显示return一下

let p = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    resolve('成功1')
  }, 10)
})

p
  .then(res1 => {
    console.log('res1--->', res1)
    // return '成功2'  // 等价于:return Promise.resolve('成功2')
    return Promise.reject('失败1')
  })
  .then(res2 => {
    console.log('res2--->', res2)
    return Promise.resolve('成功3')
    // return Promise.reject('失败1')
  })
  .then(res3=>{
    console.log('res3--->', res3)
  })
  .catch((err:string)=>{
    console.log('err--->',err )
  })

3.2 链式编程-基本使用

// 链式编程回调地狱写法
const req = http.createHttp()
req.request('接口1')
  .then(res1 => {
    return req.request('接口2?p=接口1的结果res1')
  })
  .then(res2 => {
    return req.request('接口3?p=接口2的结果res2')
  })
  .then(res3 => {
    return req.request('接口4?p=接口3的结果res3')
  })
  .then(res4 => {
    return req.request('接口5?p=接口4的结果res4')
  })
 .then(res5 => {
    return req.request('接口6?p=接口5的结果res5')
  })
 .then(res6 => {
    
  })

作用: Promise的链式编程是用来解决 回调函数地狱 的一种写法,让 多层嵌套的代码 变得可读性强

3.3 链式编程-实际应用

省市区案例

3

回调函数炼狱式写法

getList() {
    req.request('https://hmajax.itheima.net/api/province')
      .then(res => {
        // 获取第一个省份的名字
        let obj: iRes = JSON.parse(res.result.toString())
        let pname = obj.list[0]
        //   2. 刷新页面中的省份列的数据
        this.list[0] = obj.list

        // 获取市
        req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(pname)}`)
          .then(res1 => {
            let cityobj: iRes = JSON.parse(res1.result.toString())
            this.list[1] = cityobj.list

            // 获取区
            req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(pname)}&cname=${encodeURIComponent(cityobj.list[0])}`)
              .then(res2 => {
                let areaobj: iRes = JSON.parse(res2.result.toString())
                this.list[2] = areaobj.list
              })
          })

      })
  }

链式编程式写法

  getList1() {
    // 链式编程
    //  promse对象.then(()=>{ return p }).then(()=>{ return p1 }).....catch()
    //  1. 获取请求省份的promise对象
    req.request('https://hmajax.itheima.net/api/province')
      .then(res => {
        let pobj: iRes = JSON.parse(res.result.toString())
        //   2. 刷新页面中的省份列的数据
        this.list[0] = pobj.list
        this.pname = pobj.list[0]
        //   3. return一个市的接口请求Promise对象
        return req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(this.pname)}`)
      })
      .then(res1 => {
        // 4. 获取市的相关数据
        let cityobj: iRes = JSON.parse(res1.result.toString())
        this.list[1] = cityobj.list

        //   5.  return一个区的接口请求Promise对象
        return req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(this.pname)}&cname=${encodeURIComponent(cityobj.list[0])}`)

      })
      .then(res2 => {
        //   6. 区的数据
        let areaobj: iRes = JSON.parse(res2.result.toString())
        this.list[2] = areaobj.list
      })
      .catch((err: string) => {
        AlertDialog.show({ message: err })
      })
  }

4 async 函数

Promise 的链式编程虽然不用嵌套了,但是依旧有回调函数

我们可以使用 async 函数 结合 await来进一步优化,让代码变得简单和易读

Promise的链式编程写法

const req = http.createHttp()
req.request('https://hmajax.itheima.net/api/province')
    .then(res=>{
      let obj: iRes = JSON.parse(res.result.toString())
      this.multi[0] = obj.list
      return req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent('河北省')}`)
    })
    .then(res => {
      let obj: iRes = JSON.parse(res.result.toString())
      this.multi[1] = obj.list
      return  req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent('河北省')}&cname=${encodeURIComponent('石家庄市')}`)
    })
    .then(res => {
      let obj: iRes = JSON.parse(res.result.toString())
      this.multi[2] = obj.list
    })

async和await结合优化

 async getData() {
    const req = http.createHttp()
    let res1 = await req.request('https://hmajax.itheima.net/api/province')
    let res2 = await req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent('河北省')}`)
    let res3 = await req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent('河北省')}&cname=${encodeURIComponent('石家庄市')}`)

    let prov:iRes = JSON.parse(res1.result.toString())
    let city:iRes = JSON.parse(res2.result.toString())
    let area:iRes = JSON.parse(res3.result.toString())

    this.multi[0] = prov.list
    this.multi[1] = city.list
    this.multi[2] = area.list
  }

4.1 async/await基础

4.1.1 async/await是什么?

async/await是一种用于处理异步操作的Promise语法糖

通过使用async关键字声明一个函数为异步函数(返回值是Promise类型)

使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。

4.1.2 async/await基本语法

核心步骤:

  1. async 修饰函数
  2. await 等待成功(Promise 对象)
async function func() {
  // await 获取到的是 之后 Promise 对象的成功结果
  const res1 = await Promise对象1
  const res2 = await Promise对象2
  const res3 = await Promise对象3
}

//执行func函数
func()

举例

// 获取一个随机数,返回一个Promise对象
function getRandom() {
  return new Promise<string>((resolve, reject) => {
    let num = Math.floor(Math.random() * 100)
    resolve(num.toString())
  })
}
// 定义async函数func,里面使用await等待Promise对象返回结果
async function call() {
  let res = await getRandom()
  console.log(`res-->`, res)
  let res1 = await getRandom()
  console.log(`res-->`, res1)
  let res3 = await 100 
  console.log(`res-->`, res3)
}
call()

4.2 async函数和await的特点

  1. async函数的特点

1.async修饰的函数默认返回的是Promise对象, 所以可以放到await关键字后面来调用

2.async修饰的函数内部return的数据需要使用 await 或者 .then() 或者.catch 来接收

  1. await的特点

1.await关键字必须放在async修饰的函数中才能使用

2.await关键字后面是一个Promise对象,如果是一个普通值会自动转为Promise对象来执行

3.await会等待其后面的Promise对象的成功执行状态,将结果值赋值给 = 号前面的变量

await 如果后面的函数执行时间很长,会卡住调用方法的执行 sync与await使用场景:不能使用在花费很长时间的异步处理上 这种情况请使用.then方式来处理

如果Promise是失败状态,则不会再往下继续执行

如果想要执行,需要使用try/catch来捕获错误

4.3 try/catch捕获错误

使用 async 之后需要try/catch 来捕获异常

注意: try-catch可以用来捕获任意的异常,并不仅仅局限于 async 函数

try/catch基本语法:

  try {
    // 需要被执行的语句
    //一旦出错,就会触发catch中的代码执行
  } catch (error) {
    // error 接收错误信息
    // 处理错误信息代码
  }

举例

// 获取一个随机数,返回一个Promise对象
function randomNum() {
  return new Promise<string>((resolve, reject) => {
    setTimeout(() => {
      const num = Math.floor(Math.random() * 100)
      reject(num.toString())
    }, 2000)
  })
}

// 定义async函数func,里面使用await等待Promise对象返回结果
async function func() {
  console.log('run--->begin')
  //由于Promise对象的执行状态为拒绝(失败状态),则后面代码不会再执行
  // 我们需要使用try/catch来捕获异常,让代码能够继续往下执行
  try {
    const num1 = await randomNum()
    console.log('num1=', num1)
  } catch (err) {
    console.error('err--->', err)
  }
  console.log('run--->end')

}

func()

运行结果:

5

4.4. async/await改造省市区数据获取

import { http } from '@kit.NetworkKit'

const req = http.createHttp()

interface IResponse {
  message: string
  list: string[]
}


@Entry
@Component
struct Day03_06_AreaChange {
  @State message: string = '居住地选择';
  @State range: string[][] = []
  @State selected: number[] = [0, 0, 0]
  // 这部分信息的目的是渲染到页面上
  @State values: string[] = ['北京', '北京市', '东城区']
  // 请求对象
  req: http.HttpRequest = http.createHttp()
  @State showSheet: boolean = false
  timeID: number = -1

  aboutToAppear(): void {
    this.getlist()
  }

  async getlist() {
    try {
      let resProvince = await this.getPData()
      let ProvinceObj: IResponse = JSON.parse(resProvince.result.toString())
      this.range[0] = ProvinceObj.list
      let resCity = await this.getCData(ProvinceObj.list[0])
      let cityObj: IResponse = JSON.parse(resCity.result.toString())
      this.range[1] = cityObj.list
      let resArea = await this.getAData(ProvinceObj.list[0], cityObj.list[0])
      let areaObj: IResponse = JSON.parse(resArea.result.toString())
      this.range[2] = areaObj.list
    } catch (err) {
      AlertDialog.show({
        message: err
      })
    }


  }

  async getPData() {
    return req.request(`https://hmajax.itheima.net/api/province`)
  }

  async getCData(pname: string) {
    return req.request(`https://hmajax.itheima.net/api/city?pname=${encodeURIComponent(pname)}`)
  }

  async getAData(pname: string, cname: string) {
    return req.request(`https://hmajax.itheima.net/api/area?pname=${encodeURIComponent(pname)}&cname=${encodeURIComponent(cname)}`)
  }

  build() {
    Column({ space: 10 }) {
      // 标题
      Text(this.message)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .textAlign(TextAlign.Center)
        .width('100%')
        .margin({ bottom: 20 })
      //
      Row({ space: 10 }) {
        Text('居住地:')
          .fontWeight(FontWeight.Bold)
        Text(this.values.join('/'))
          .layoutWeight(1)
          .fontColor(Color.Gray)
          .onClick(() => {
            this.showSheet = true
          })
        Image($r('app.media.ic_public_arrow_right'))
          .width(20)
      }

      Divider()
      Blank()
    }
    .height('100%')
    .width('100%')
    .alignItems(HorizontalAlign.Start)
    .padding(20)
    .bindSheet($$this.showSheet, this.areaSheet(), {
      height: 300
    })
  }

  @Builder
  areaSheet() {
    Column() {
      TextPicker({
        range: this.range,
        selected: $$this.selected,
      })
        .canLoop(false)
        .onChange((value, index) => {
          clearTimeout(this.timeID)
          this.timeID = setTimeout(async () => {
            if (value[0] != this.values[0]) { // 切换省
              let resCity = await this.getCData(value[0])
              let cityObj: IResponse = JSON.parse(resCity.result.toString())
              this.range[1] = cityObj.list

              let resArea = await this.getAData(value[0], cityObj.list[0])
              let areaObj: IResponse = JSON.parse(resArea.result.toString())
              this.range[2] = areaObj.list
              this.selected = [this.range[0].indexOf(value[0]), 0, 0]
              this.values = [value[0], cityObj.list[0], areaObj.list[0]]

            } else if (value[0] == this.values[0] && value[1] != this.values[1]) { // 切换市
              let resArea = await this.getAData(value[0], value[1])
              let areaObj: IResponse = JSON.parse(resArea.result.toString())
              this.range[2] = areaObj.list
              this.selected = [this.range[0].indexOf(value[0]), this.range[1].indexOf(value[1]), 0]
              this.values = [value[0], value[1], areaObj.list[0]]
            }
            this.values = value as string[]
          }, 300)
        })
    }
  }
}

运行截图

5

5 Promise 静态方法

在日常开发中除了使用 Promise 对象以外,还可以通过 Promise 提供的静态方法来管理多个异步

5.1 Promise.resolve

是什么: 返回一个成功原因的 Promise 对象

基本用法

Promise.resolve('成功原因')
  .then(res => {
    AlertDialog.show({ message: res })
  })

5.2 Promise.reject

是什么: 返回一个拒绝原因的 Promise 对象

基本用法

Promise.reject('拒绝原因')
  .catch((err: string) => {
    AlertDialog.show({ message: err })
  })

5.3 Promise.race

是什么: Promise.race()方法‌用于处理一组异步操作,并返回第一个完成的异步操作的结果

场景: 多个服务器提供相同的数据,但响应时间不同,你想要最快的那个服务器给你响应数据

基本用法

const p1 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    resolve('1')
  }, 2000)
})

const p2 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    reject('2')
  }, 1000)
})

// Promise.race方法作用:可以执行一组异步对象,返回第一个执行完成的异步对象的结果
Promise.race([p1, p2])
  .then(res => {
    console.log('race执行结果--->', res)
  })
  .catch((err:string)=>{
    console.log('err race执行结果--->', err)
  })

/*race方法,可以执行一组异步对象
  注意点:最快的那个异步对象如果是成功状态,则使用.then来接受结果
  否则使用.catch来接收结果

  应用场景:多个服务器提供相同的数据,但响应时间不同,你想要最快的那个服务器给你响应数据

 */

案例

一次性获取北京,上海,广州三个城市的城市编码信息,把最快响应的哪个接口数据打印出来

import { http } from '@kit.NetworkKit'

async function func(){
  const req = http.createHttp()
  const p1 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('北京')}`)
  const p2 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('上海')}`)
  const p3 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('广州')}`)

  // 结果是一个数组
  const res = await Promise.race([p1, p2, p3])

  // 打印
  console.log(``, res.result)
}
func()

运行结果

通过多次运行打印可以看出哪个接口反应快,就会输出哪个接口的数据

6

5.4 Promise.all

是什么:

Promise.all方法用于处理多个Promise实例

如果所有Promise实例都成功完成,将所有成功的结果作为一个数组返回

如果任何一个Promise实例失败返回第一个失败的Promise实例的原因

场景: 同时请求多个API

基本用法

 const p1 = new Promise<string>((resolve, reject) => {
      setTimeout(() => {
        resolve('1')
      }, 2000)
    })

const p2 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    reject('2')
  }, 1000)
})

const p3 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    reject('3')
  }, 1000)
})

Promise.all([p1, p2, p3]).then((res) => {
  console.log('res:', res)
}, (err: string) => {
  console.log('err:', err)
})

案例

一次性获取北京,上海,广州三个城市的城市编码信息,打印出来


import { http } from '@kit.NetworkKit'

async function func(){
  const req = http.createHttp()
  const p1 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('北京')}`)
  const p2 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('上海')}`)
  const p3 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('广州')}`)

  // 结果是一个数组
  const res = await Promise.all([p1, p2, p3])

  // 打印
  console.log(``, JSON.stringify(res[0].result))
  console.log(``, JSON.stringify(res[1].result))
  console.log(``, JSON.stringify(res[2].result))
}
func()

运行结果

7

5.5 Promise.allSettled

是什么:

allSettled 可以获取所有的结果,无论成功失败

基本用法

const p1 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    resolve('1')
  }, 2000)
})
const p2 = new Promise<string>((resolve, reject) => {
  setTimeout(() => {
    reject('2')
  }, 1000)
})
Promise.allSettled([p1, p2, 'itheima'])
  .then((res) => {
    console.log('res:', JSON.stringify( res))
    //   [{"status":"fulfilled","value":"1"},{"status":"rejected","reason":"2"},{"status":"fulfilled","value":"itheima"}]
  }, (err: string) => {
    console.log('err:', err)
  })

案例

一次性获取北京,上海,广州三个城市的城市编码信息,打印出来

async function func(){
  const req = http.createHttp()
  const p1 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('北京')}`)
  const p2 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('上海')}`)
  const p3 = req.request(`https://hmajax.itheima.net/api/weather/city?city=${encodeURIComponent('广州')}`)

  // 结果是一个数组
  const res = await Promise.allSettled([p1, p2, p3])

  // 打印
  console.log(``, JSON.stringify(res[0]))
  console.log(``, JSON.stringify(res[1]))
  console.log(``, JSON.stringify(res[2]))
}

运行结果

9

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

2

mau123789
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值