Flutter - Dart 基础(单线程异步中的 Future)

217 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

定义耗时操作

模拟一个网络请求,该网络请求耗时3秒,之后返回数据

void main(List<String> args) {
    print("开始----");
    print(DateTime.now());
    
    print(getNetworkData());

    print(DateTime.now());
    print("结束----");
}


String getNetworkData() {
    sleep(Duration(seconds: 3));
    return "dart";
}

log:

网络请求阻塞 main() 函数,必须等待耗时操作完成才会执行之后的逻辑

截屏2022-06-20 上午12.20.14.png

关于 Future

什么是 Future

  • 在 Dart 中,Future 是指延迟运行的对象 Future<T>,用来表示在将来某时获取一个值的方式

  • 这个 Future 对象是 Dart 内置的,有自己的队列策略,它将要操作的事件放入EventQueue 中,在队列中的事件按照先进先出的原则去逐一处理事件,当事件处理完成后,将结果返回给 Future 对象

    void main(List<String> args) {
    
        print("开始----");
        print(DateTime.now());
        print(getNetworkData());
        print(DateTime.now());
        print("结束----");
    }
    
    Future<String> getNetworkData() {
        return Future<String>(() {
            sleep(Duration(seconds: 5));
            return "dart";
        });
    }
    

    log:

    将耗时操作放入 Future 对象中,没有出现阻塞现象,但是打印出的内容是 Future 对象

    截屏2022-06-20 上午12.21.52.png

Future 的回调函数

Future 的调用者可以注册回调

  • 一种是成功回调函数。通过 .then() 的方式来监听 Future 异步执行完成时获取到的结果

  • 一种是错误回调函数。通过 .catchError() 的方式来监听 Future 异步执行失败或者出现异常时的错误信息

void main(List<String> args) {
    print("开始----");
    print(DateTime.now());

    final future = getNetworkData();
    future.then((value) {
        print(value);
    }).catchError((error) {
        print(error);
    });

    print(DateTime.now());
    print("结束----");
}

Future<String> getNetworkData() {

    return Future<String>(() {
        sleep(Duration(seconds: 5));
        
        // 返回正确的信息
        return "dart";
        
        // 返回错误的信息
        // throw Exception("网络请求出现错误");
    });
}

log:

正确信息 截屏2022-06-20 上午12.23.48.png

错误信息 截屏2022-06-20 上午12.24.56.png

Future 的状态

Future 在执行中,可以通过 whenComplete() 来监听 Future 是否执行完成。结果有两种状态

  • 完成状态

    Future 返回正确会错误的回调之后,代表 Future 内部操作已完成,这个状态为完成状态

  • 未完成状态

    执行 Future 内部的操作时,还没有返回正确或错误的回调时的状态,这个状态为未完成状态

void main(List<String> args) {

    print("开始----");
    print(DateTime.now());
    
    final future = getNetworkData();
    
    future.then((value) {
        print(value);
    }).catchError((error) {
        print(error);
    }).whenComplete(() {
        print("完成");
    });
    
    print(DateTime.now());
    print("结束----");
}

Future<String> getNetworkData() {
    return Future<String>(() {
        sleep(Duration(seconds: 5));
        
        // 返回正确的信息
        return "dart";
        
        // 返回错误的信息
        // throw Exception("网络请求出现错误");
    });
}

log:

截屏2022-06-20 上午12.26.38.png

Future 的链式调用

在某些情况下,可以在 then() 中继续返回值,会在下一个链式的 then() 调用回调函数中拿到返回的结果。但是当 Future 在完成时出现错误,而且它没有后续与之串起来的 Future,则这个错误消息将会被转发给全局错误处理程序。这种机制确保了错误不会被自动删除,但是,这也意味着开发者应该尽早注册错误处理函数以便 Future 一旦返回 errorerror 处理程序就会立进行处理

void main(List<String> args) {
    print("开始----");
    print(DateTime.now());
    
    final future = getNetworkData();
    
    future.then((value) {
        print(value);
        return "dart2";
    }).then((value) {
        print(value);
    }).catchError((error) {
        print(error);
    }).whenComplete(() {
        print("完成");
    });

    print(DateTime.now());
    print("结束----");
}

Future<String> getNetworkData() {

    return Future<String>(() {

        sleep(Duration(seconds: 5));

        return "dart";
        // throw Exception("网络请求出现错误");
    });
}

log:

截屏2022-06-20 上午12.28.21.png

Future 的其他 API

  • Future.delayed(时间, 回调函数)

    在延迟一定时间时执行回调函数,执行完回调函数后会执行 then()whenComplete() 的回调

    void main(List<String> args) {
        print("开始----");
        
        Future.delayed(Duration(seconds: 3), () {
            return "延时3秒";
        }).then((value) {
            print(value);
        }).whenComplete(() {
            print("完成");
        });
        
        print("结束----");
    }
    

    log: 截屏2022-06-20 上午12.29.38.png

  • Future.value(value)

    直接获取一个完成的 Future,该 Future 会直接调用 then() 的回调函数

    void main(List<String> args) {
    
        print("开始----");
    
        Future.value("dart").then((value) {
            print(value);
        });
        
        print("结束----");
    }
    

    log: 截屏2022-06-20 上午12.30.49.png

  • Future.error(object)

    直接获取一个完成的 Future,但是是一个发生异常的 Future ,该 Future 会直接调用 catchError() 的回调函数

    void main(List<String> args) {
    
        print("开始----");
    
        Future.error(Exception("错误信息")).catchError((error) {
            print(error);
        });
    
        print("结束----");
    }
    

    log:

    截屏2022-06-20 上午12.31.50.png

关于 async 和 await

  • async:标记某个方法为异步方法(一般执行耗时操作),在声明方法的时候使用
  • await:等待某个异步方法执行完毕,是“等待”之意,所以要在调用耗时方法的时候使用
void main(List<String> args) {
    print("开始----");
    
    final future = getNetworkData();
    
    future.then((value) {
        print(value);
    }).catchError((error) {
        print(error);
    }).whenComplete(() {
        print("完成");
    });
    
    print("结束----");
}

Future<String> getNetworkData() async {
    var reslut = await Future.delayed(Duration(seconds: 3), () {
        const str = "dart";
        print(str);
        return str;
    });
    return "请求数据:" + reslut;
}

log: 截屏2022-06-20 下午7.45.43.png

步骤分析:

  1. 因为 Future.delayed() 返回的是一个 Future对象
  2. Future.delayed() 函数前加 await,那么以下的逻辑就要等待 Future.delayed() 的执行完毕出结果
  3. await 关键字必须存在于 async 函数中,所以需要将 getNetworkData 函数定义成 async 函数
  4. 返回值是一个 Future 对象,如果没有返回 Future 对象,会自动将返回值包装成 Future 对象