[Flutter跨平台]六、Dart核心3-异步、泛型、异常处理

93 阅读11分钟

Dart是单线程的

同步的例子

import 'dart:io';

void main() {
  // // 1.验证dart是单线程, 此时必然是getNetwork()这行执行完才会执行之后的打印bbb;如果是多线程语言,不会等到这行代码执行完
  print('开始执行主函数--同步');
  print(getNetwork());
  print('bbb');
}

/**
 * 1. 模拟网络请求  (此时是同步的)
 */
String getNetwork() {
  sleep(Duration(seconds: 3));
  return '获取了网络数据';
}

1. 异步编程

异步编程分为两种:

  1. 多线程:如C++、Java、鸿蒙,就是用的多线程方式;通过线程间的通信方式拿到数据主线程
  2. 单线程:单线程+事件循环;JS、Dart就是的;
    (就是一个线程,同步的排到线程上面去(不能是耗时的),耗时的放在“异步”上面,同步的做完了,就执行异步的,不停这样循环)

1.1. Future

1.1.1. 基本使用

import 'dart:io';

void main() {
  // 使用Future
  print('开始执行主函数--同步');
  getNetwork().then((res) {
    print(res);
  }).catchError((err) {
    print(err);
  });
  print('我是不能被阻塞的同步任务');
}

// 在鸿蒙中针对这些耗时的操作是放在Promiss里面;而Dart也有类似的东西,叫:Future

// 以下就是Future的写法  (这里是模拟把异步的内容写在Future中,这个Futurn是什么呢?就是能自动将本来不异步的变为异步)
Future<String> getNetwork() {
  return Future(() {
    sleep(Duration(seconds: 3));
    return '成功获取了网络数据';
  });
}

1.1.2. Future链式调用 (.then().catchError()这种写法就是链式调用)

链式调用:就是写.then().catchError()这种写法就是链式调用;

重点:在实际使用中,这个Future不一定是自己写出来创建的,也可能是调用内部API或第三方那个API获取到一个Future;

鸿蒙中的Promise有三种状态:当初始态 进入 成功态或失败态时 都是不能回退的;

  1. 初始态(pending):表示异步操作尚未完成,既没有被兑现,也没有被拒绝;
  2. 成功态(fulfilled):当Promise实例中异步任务成功完成并返回结果时,状态从初始态 进入 成功态
  3. 失败态(rejected):当Promise实例中异步任务执行失败时;状态从初始态 进入 失败态

但Dart中的Future只有两种状态

  1. 未完成状态(uncompleted):执行Future的异步操作时,当运行后还在 等待时还没返回结果时(例如案例中模拟的延时) 此时就是未完成状态;
  2. 完成状态(completed):当Future的异步操作执行完成 并返回结果抛出一个异常,这都是完成状态(不像Promise);
import 'dart:io';

void main() {
  // // 1.验证dart是单线程, 此时必然是getNetwork()这行执行完才会执行之后的打印bbb;如果是多线程语言,不会等到这行代码执行完
  // print('开始执行主函数--同步');
  // print(getNetwork());
  // print('bbb');

  // 2.使用Future
  print('开始执行主函数--同步');
  getNetwork().then((res) {
    print(res);
  }).catchError((err) {
    print(err);
  });
  print('我是不能被阻塞的同步任务');
}

// 在鸿蒙中针对这些耗时的操作是放在Promiss里面;而Dart也有类似的东西,叫:Future
/**
 * 1. 模拟网络请求  (此时是同步的)
 */
// String getNetwork() {
//   sleep(Duration(seconds: 3));
//   return '获取了网络数据';
// }

// 2. 以下就是Future的写法  (这里是模拟把异步的内容写在Future中,这个Futurn是什么呢?就是能自动将本来不异步的变为异步)
Future<String> getNetwork() {
  return Future(() {
    sleep(Duration(seconds: 3));
    // return '成功获取了网络数据';
    throw '网络请求出现了异常'; //这就是抛出一个异常,类比是网络请求出现错误时,在上面写的catchError就能捕获到(只会打印出这里自己设定的文字,而不会报错);
  });
}

1.1.3. Future链式调用小练习

// 用户先登录,登录成功之后拿到token,然后再保存token到本地

import 'dart:io';

void main() {
  print('同步任务---a');
  //异步任务
  login().then((tok) {
    // 拿到token并保存到本地
    saveToken(tok).then((res) {
      print('成功...$res');
    });
  }).catchError((err) {
    print('出现了错误:$err');
  });

  print('同步任务---b');
}

/**
 * 登录
 */
Future<String> login() {
  return Future(() {
    sleep(Duration(seconds: 3));
    print('登录完成');
    return '012qweqweqweqweqweqw';
  });
}

/**
 * 保存token
 */
Future<bool> saveToken(String token) {
  return Future(() {
    sleep(Duration(seconds: 2));
    print('token已保存,token是$token');
    return true;
  });
}

1.2. async和await

// 用户先登录,登录成功之后拿到token,然后再保存token到本地

import 'dart:io';

void main() {
  print('同步任务---a');
  //异步任务
  logSa();

  print('同步任务---b');
}

logSa() async {
  try {
    String token = await login();
    bool saveSta = await saveToken(token);
    if (saveSta) {
      print('整个操作结果成功');
    } else {
      print('整个操作结果失败');
    }
  } catch (e) {
    print(e);
  }
}

/**
 * 登录
 */
Future<String> login() {
  return Future(() {
    sleep(Duration(seconds: 3));
    print('登录完成');
    return '012qweqweqweqweqweqw';
  });
}

/**
 * 保存token
 */
Future<bool> saveToken(String token) {
  return Future(() {
    sleep(Duration(seconds: 2));
    print('已获取到token,token是$token');
    // return true;//模拟操作成功
    throw Exception('出现了异常'); //模拟操作失败
  });
}

1.3. 泛型

1.3.1. dynamic类型 及 泛型的用法-List/Map定义中

/**
 * dynamic 会关闭编译器的类型检查
 * 1. 所以dynamic声明的变量在修改时不会检查类型
 * 2. 代码在编译器不会报错,但是在运行时就会报错
 */
void main() {
  // 1. List/Map不用泛型的写法, 此时里面可以写任何类型
  // List arr = [11, 'asd', false];
  // Map m = {123: 'qq', '阿斯达': 123, false: true};

  // 2. 使用泛型的写法, 此时可以限制里面只能写什么类型
  List<num> arr = [11, 22, 15]; //这样就只能写num数字类型了
  Map<String, dynamic> m = {
    '123': 'qq',
    '阿斯达': 123,
    'false': true
  }; //此时<String, dynamic>中的dynamic是任意类型, <String, dynamic>说明里面的键值对格式必须按照这个格式来:{键必须是String : 值可以是任意类型, 键必须是String : 值可以是任意类型...}
}

1.3.2. 泛型-函数

/**
 * 泛型的使用: 使用泛型可以减少重复的代码
 * 封装函数: 接收字符串就返回字符串,接收数字就返回数字,接收bool就返回bool
 */

void main() {
  // // 1.普通封装
  // getValue(5);
  // getValue('aaa'); //此时入参不是数字就会报错,不灵活
  // getValue(true); //此时入参不是数字就会报错,不灵活

  // 2.基于泛型封装
  getValue<num>(12);
  getValue<String>('aaa');
  getValue<bool>(true);
}

// // 1.普通封装
// num getValue(num number) {
//   return number;
// }

// 2.基于泛型封装 在方法后面加一个<T>,也相当于一个入参,只不过这个入参是 类型(在调用的时候也需要加<>尖括号,然后尖括号里要写上具体的 "类型入参");
// 方法中写了<T>后, 它在方法体中需要用到类型的地方都可以使用
T getValue<T>(T numbera) {
  return numbera;
}

1.4. 异常处理

  • try...catch...finally
  • if...else: 处理返回的是true或false的 ,或者说返回的是正常或不正常的,如果不正常,就手动抛出异常;
void main() {
  // 1. 捕获异常:try catch
  // try {
  //   dynamic name = 'itheima';
  //   name.haha();
  // } catch (e) {
  //   print(e);
  // } finally {
  //   // 无论是否有异常都会执行这个代码块
  //   print('finally');
  // }

  // 2. 手动抛出异常:判断字符串是否相等,如果不相等手动抛出异常
  try {
    String str = 'itcast';
    if (str == 'yjh') {
      print('ok');
    } else {
      // 手动抛出异常
      throw Exception('字符串不相等');
    }
  } catch (e) {
    print(e);
  }
}
```**Dart是单线程的**

## 同步的例子

import 'dart:io';

void main() { // // 1.验证dart是单线程, 此时必然是getNetwork()这行执行完才会执行之后的打印bbb;如果是多线程语言,不会等到这行代码执行完 print('开始执行主函数--同步'); print(getNetwork()); print('bbb'); }

/**

    1. 模拟网络请求 (此时是同步的) */ String getNetwork() { sleep(Duration(seconds: 3)); return '获取了网络数据'; }

# 1. 异步编程

异步编程分为两种:

1.  **多线程**:如C++、Java、鸿蒙,就是用的多线程方式;通过**线程间的通信方式****拿到数据****主线程**1.  **单线程**:单线程+事件循环;JS、Dart就是的;  
    (就是一个线程,同步的排到线程上面去(不能是耗时的),耗时的放在“异步”上面,同步的做完了,就执行异步的,不停这样循环)

## 1.1. Future

### 1.1.1. 基本使用

import 'dart:io';

void main() { // 使用Future print('开始执行主函数--同步'); getNetwork().then((res) { print(res); }).catchError((err) { print(err); }); print('我是不能被阻塞的同步任务'); }

// 在鸿蒙中针对这些耗时的操作是放在Promiss里面;而Dart也有类似的东西,叫:Future

// 以下就是Future的写法 (这里是模拟把异步的内容写在Future中,这个Futurn是什么呢?就是能自动将本来不异步的变为异步) Future getNetwork() { return Future(() { sleep(Duration(seconds: 3)); return '成功获取了网络数据'; }); }


### 1.1.2. **Future**链式调用 (.then().catchError()这种写法就是链式调用)

**链式调用**:就是写.then().catchError()这种写法就是链式调用;

**重点**:在实际使用中,这个Future不一定是自己写出来创建的,也可能是调用内部API或第三方那个API获取到一个Future;

**鸿蒙中的Promise有三种状态**:当初始态 进入 成功态或失败态时 都是不能回退的;

1.  初始态(pending):表示异步操作尚未完成,既没有被兑现,也没有被拒绝;
1.  成功态(fulfilled):当Promise实例中异步任务成功完成并返回结果时,状态从初始态 进入 **成功态**1.  失败态(rejected):当Promise实例中异步任务执行失败时;状态从初始态 进入 **失败态****但Dart中的Future只有两种状态**1.  未完成状态(uncompleted):执行Future的异步操作时,当运行后还在 **等待时还没返回结果时**(例如案例中模拟的延时) 此时就是未完成状态;
1.  完成状态(completed):当Future的异步**操作执行完成 并返回结果****抛出一个异常**,这都是完成状态(不像Promise);

import 'dart:io';

void main() { // // 1.验证dart是单线程, 此时必然是getNetwork()这行执行完才会执行之后的打印bbb;如果是多线程语言,不会等到这行代码执行完 // print('开始执行主函数--同步'); // print(getNetwork()); // print('bbb');

// 2.使用Future print('开始执行主函数--同步'); getNetwork().then((res) { print(res); }).catchError((err) { print(err); }); print('我是不能被阻塞的同步任务'); }

// 在鸿蒙中针对这些耗时的操作是放在Promiss里面;而Dart也有类似的东西,叫:Future /**

    1. 模拟网络请求 (此时是同步的) */ // String getNetwork() { // sleep(Duration(seconds: 3)); // return '获取了网络数据'; // }

// 2. 以下就是Future的写法 (这里是模拟把异步的内容写在Future中,这个Futurn是什么呢?就是能自动将本来不异步的变为异步) Future getNetwork() { return Future(() { sleep(Duration(seconds: 3)); // return '成功获取了网络数据'; throw '网络请求出现了异常'; //这就是抛出一个异常,类比是网络请求出现错误时,在上面写的catchError就能捕获到(只会打印出这里自己设定的文字,而不会报错); }); }


### 1.1.3. **Future**链式调用小练习

// 用户先登录,登录成功之后拿到token,然后再保存token到本地

import 'dart:io';

void main() { print('同步任务---a'); //异步任务 login().then((tok) { // 拿到token并保存到本地 saveToken(tok).then((res) { print('成功...res'); }); }).catchError((err) { print('出现了错误:err'); });

print('同步任务---b'); }

/**

  • 登录 */ Future login() { return Future(() { sleep(Duration(seconds: 3)); print('登录完成'); return '012qweqweqweqweqweqw'; }); }

/**

  • 保存token */ Future saveToken(String token) { return Future(() { sleep(Duration(seconds: 2)); print('token已保存,token是$token'); return true; }); }

## 1.2. asyncawait

// 用户先登录,登录成功之后拿到token,然后再保存token到本地

import 'dart:io';

void main() { print('同步任务---a'); //异步任务 logSa();

print('同步任务---b'); }

logSa() async { try { String token = await login(); bool saveSta = await saveToken(token); if (saveSta) { print('整个操作结果成功'); } else { print('整个操作结果失败'); } } catch (e) { print(e); } }

/**

  • 登录 */ Future login() { return Future(() { sleep(Duration(seconds: 3)); print('登录完成'); return '012qweqweqweqweqweqw'; }); }

/**

  • 保存token */ Future saveToken(String token) { return Future(() { sleep(Duration(seconds: 2)); print('已获取到token,token是$token'); // return true;//模拟操作成功 throw Exception('出现了异常'); //模拟操作失败 }); }

## 1.3. 泛型

### 1.3.1. dynamic类型 及 泛型的用法-List/Map定义中

/**

  • dynamic 会关闭编译器的类型检查
    1. 所以dynamic声明的变量在修改时不会检查类型
    1. 代码在编译器不会报错,但是在运行时就会报错 */ void main() { // 1. List/Map不用泛型的写法, 此时里面可以写任何类型 // List arr = [11, 'asd', false]; // Map m = {123: 'qq', '阿斯达': 123, false: true};

// 2. 使用泛型的写法, 此时可以限制里面只能写什么类型 List arr = [11, 22, 15]; //这样就只能写num数字类型了 Map<String, dynamic> m = { '123': 'qq', '阿斯达': 123, 'false': true }; //此时<String, dynamic>中的dynamic是任意类型, <String, dynamic>说明里面的键值对格式必须按照这个格式来:{键必须是String : 值可以是任意类型, 键必须是String : 值可以是任意类型...} }


### 1.3.2. 泛型-函数

/**

  • 泛型的使用: 使用泛型可以减少重复的代码
  • 封装函数: 接收字符串就返回字符串,接收数字就返回数字,接收bool就返回bool */

void main() { // // 1.普通封装 // getValue(5); // getValue('aaa'); //此时入参不是数字就会报错,不灵活 // getValue(true); //此时入参不是数字就会报错,不灵活

// 2.基于泛型封装 getValue(12); getValue('aaa'); getValue(true); }

// // 1.普通封装 // num getValue(num number) { // return number; // }

// 2.基于泛型封装 在方法后面加一个,也相当于一个入参,只不过这个入参是 类型(在调用的时候也需要加<>尖括号,然后尖括号里要写上具体的 "类型入参"); // 方法中写了后, 它在方法体中需要用到类型的地方都可以使用 T getValue(T numbera) { return numbera; }


## 1.4. 异常处理

-   try...catch...finally
-   if...else: 处理返回的是truefalse的 ,或者说返回的是正常或不正常的,如果不正常,就手动抛出异常;

void main() { // 1. 捕获异常:try catch // try { // dynamic name = 'itheima'; // name.haha(); // } catch (e) { // print(e); // } finally { // // 无论是否有异常都会执行这个代码块 // print('finally'); // }

// 2. 手动抛出异常:判断字符串是否相等,如果不相等手动抛出异常 try { String str = 'itcast'; if (str == 'yjh') { print('ok'); } else { // 手动抛出异常 throw Exception('字符串不相等'); } } catch (e) { print(e); } }