饿补一下Flutter中Http请求的异步操作。

Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作、延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到卡顿,于是通常用异步处理来解决这个问题。

Dart异步编程有两种方式:Future和Stream

Future相当于40米大砍刀,Stream相当于一捆40米大砍刀。dart提供了关键字async(异步)和await(延迟执行),相当于普通的便捷的小匕首,而小匕首是我们平时经常用到的。

当遇到有需要延迟的运算(async)时,将其放入到延迟运算的队列(await)中去,把不需要延迟运算的部分先执行掉,最后再来处理延迟运算的部分。

1、async和await

async await 这两个关键字是dart语言的特性,能让你写出看起来像是“同步”的“异步”代码,先看一个方法案例:

  /*HTTP的get请求返回值为Future<String>类型,即其返回值未来是一个String类型的值*/
  /*async关键字声明该函数内部有代码需要延迟执行*/
  getData() async {    
    /*await关键字声明运算为延迟执行,然后return运算结果*/
    return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); 
  }

然后我们尝试调用这个方法,并获取返回值。

String data = getDate();

然后控制台报错了….

为什么呢?因为data是String类型,而函数getData()是一个异步操作函数,其返回值是一个await延迟执行的结果。在Dart中,有await标记的运算,其结果值都是一个Future对象,Future不是String类型,所以就报错了。

总结一下:

在请求方法中直接 return await .. .的时候,实际上返回的是一个延迟计算的Future对象。

还有两点需要注意:

  • await关键字必须在async函数内部使用
  • 调用async函数必须使用await关键字

后面两点怎么讲?

  1. 要想 return await … ,那么方法首先是 async 的,如上方方法。
  2. 使用 async 标注的方法,必须要用 await 接收返回值,比如上方方法在接收返回值时,需要加入 await ,var data = await getData();

2、什么是Future

Future表示一件“将来”会发生的事情,将来可以从Future中取到一个值。当一个方法返回一个Future的事情,发生两件事情:

  • 这个方法将某件事情排队,返回一个未完成的Future
  • 当这件事情完毕之后,Future的状态会变成已完成,这个时候就可以取到这件事情的返回值了。

要取到这个“返回值”,有两种方式:

  • 使用async配合await
  • 使用Future提供的api

我们看这两种实现方式的案例:

2.1、使用async配合await

先看个案例,等待3秒后返回‘我是用户’:

/*模拟异步加载用户信息*/
Future _getUserInfo() async{
  await new Future.delayed(new Duration(milliseconds: 3000));
  return "我是用户";
} /*加载用户信息,顺便打印时间看看顺序*/
Future _loadUserInfo() async{
  print("_loadUserInfo:${new DateTime.now()}");
  print(await _getUserInfo());
  print("_loadUserInfo:${new DateTime.now()}");
}

我们在initState中调用该方法:

@override
void initState(){
    print("initState:${new DateTime.now()}");
    _loadUserInfo();
    print("initState:${new DateTime.now()}");     super.initState();
}

打印结果如下:

I/flutter ( 1802): initState:2019-06-20 09:46:40.097339
I/flutter ( 1802): _loadUserInfo:2019-06-20 09:46:40.103542
I/flutter ( 1802): Instance of 'Future<dynamic>'
I/flutter ( 1802): initState:2019-06-20 09:46:40.108510
I/flutter ( 1802): 我是用户
I/flutter ( 1802): _loadUserInfo:2019-06-20 09:46:43.117136

what?

很明显,打印结果并没有按照串联的方式依次打印。

flutter中会改造带asyc关键字的方法,让这个方法脱离主流程,变成“后面一点”执行(通过scheduleMicrotask),所以可以让我们的程序“看起来”是顺序执行的。

2.2、Future api

我们修改一下 loadUserInfo() 方法:

/*加载用户信息,顺便打印时间看看顺序*/
  Future _loadUserInfo() async{
    print("_loadUserInfo:${new DateTime.now()}");
    _getUserInfo().then((info){
      print(info);
    });
    print("_loadUserInfo:${new DateTime.now()}");
  }

再次运行输出一下:

I/flutter ( 1802): initState:2019-06-20 09:50:32.488765
I/flutter ( 1802): _loadUserInfo:2019-06-20 09:50:32.494751
I/flutter ( 1802): _loadUserInfo:2019-06-20 09:50:32.499725
I/flutter ( 1802): Instance of 'Future<dynamic>'
I/flutter ( 1802): initState:2019-06-20 09:50:32.499970
I/flutter ( 1802): 我是用户

两次输出是有不同的,主要不同在于第二个 loadUserInfo 的日志打印,与‘我是用户’的输出顺序,为什么有差异?

await会阻塞流程,等待紧跟着的的Future执行完毕之后,再执行下一条语句,而如果用了Future.then这个api,那么就不会等待,直接执行下面的语句,等Future执行完了,再调用then这个方法。

3、总结

在请求方法中直接 return await .. .的时候,实际上返回的是一个延迟计算的Future对象。

有两点需要注意:

  • await关键字必须在async函数内部使用
  • 调用async函数必须使用await关键字

Flutter 中有两种实现异步编程的方式:Future api、 async await

日常开发中常用的是 async await Future 搭配。

flutter中的异步机制Future的更多相关文章

  1. flutter中的异步机制 Future

    饿补一下Flutter中Http请求的异步操作. Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作.延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到 ...

  2. Flutter 的异步机制Future

    Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作.延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到卡顿,于是通常用异步处理来解决这个问题. Dart ...

  3. Netty 中的异步编程 Future 和 Promise

    Netty 中大量 I/O 操作都是异步执行,本篇博文来聊聊 Netty 中的异步编程. Java Future 提供的异步模型 JDK 5 引入了 Future 模式.Future 接口是 Java ...

  4. ajax中的异步机制导致的问题

    设置async:false;即可将请求设置为同步的,所以,我们就可以实现:在ajax请求之后再执行下面的语句.

  5. JS中的异步以及事件轮询机制

    一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...

  6. 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)

    首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...

  7. Flutter 中使用Future消除Callback Hell

    /先分别定义各个异步任务 Future<String> login(String userName, String pwd){ ... //用户登录 }; Future<String ...

  8. 深入理解Spring的异步机制

    一.Spring中实现异步执行 在这里我先以事件的机制举例,注意默认情况下事件的发布与监听都是同步执行的.那么我们来看一看基于异步事件的例子该怎么写 首先还是定义事件: package com.bdq ...

  9. [译]Python中的异步IO:一个完整的演练

    原文:Async IO in Python: A Complete Walkthrough 原文作者: Brad Solomon 原文发布时间:2019年1月16日 翻译:Tacey Wong 翻译时 ...

随机推荐

  1. 62 网络编程(三)——UDP编程

    UDP编程标准步骤 服务器端 使用DatagramSocket创建服务端:DatagramSocket server = new DatagramSocket(port);//参数为自定义端口号 准备 ...

  2. 轨迹条(Trackbar)

    1.创建 createTrackbar(轨迹条名称,窗口名称,滑动条的初始位置,滑动条的最大值,回调函数XXX,不懂) 其中回调函数为 void XXX(滑动条的位置,用户数据)在c++中函数名为指向 ...

  3. java基础 接口静态方法

    /** * 从java8开始,接口当中允许定义静态方法 * 格式: * public static 返回值类型 方法名称(参数列表){ * 方法体 * } * 提示:就是将abstract或者defa ...

  4. 常用 Git 命令汇总

    Git 命令汇总 1 Git 的一些通用术语 1.1 Git 的几个区 1.2 如何标识 Git 的某次提交 2 Git 配置 2.1 配置 2.2 读取配置 2.3 与 Beyond Compare ...

  5. “分而治之”,一种AI和动画系统的架构

    译者注:随着国内游戏研发水平的不断提高,对画面品质的不断提升,同时大量手游使用Unity和Unreal 4等成熟的工具开发,动作状态机已经不是什么陌生的概念了.我们在项目开发时也大量使用了动作状态机. ...

  6. List泛型用法(转载)

    网上的List泛型用法,未验证,目测基本正确,教学用资料. 1.  List的基础.常用方法: 声明: 1.List<T> mList = new List<T>(); T为列 ...

  7. 关于OA流程相关数据表的设计

    一.前言 近期有些同学问起流程的表设计,终于有时间能写下博客,并整理下之前所发布的文章. 之前的文章讲到的表设计,没有给全且还存在漏洞,在这里向各位同学表示歉意.这是我个人最新领悟的一些流程思维,欢迎 ...

  8. MySQL常用sql语句大全

    创建数据库 1 create database dbname; 删除数据库 1 drop database dbname; 选择数据库 1 use dbname; 创建表 12345678 CREAT ...

  9. 【Mysql技术内幕InnoDB存储引擎】读书笔记

    一.存储引擎 1.InnoDB引擎 设计目标是面向在线事务(OLTP)处理的应用. 支持事务.行级锁.通过多版本并发控制(MVCC)支持高并发.提供一致性非锁定读.next-key locking避免 ...

  10. 英语hecatolite月长石hecatolite月光石

    月长石英文名字为hecatolite即月光石.当白色的光照到宝石上因宝石内特殊的结构而产生干涉颜色,在宝石表面可见到白至淡蓝色的闪光,犹如朦胧月光.这是由于正长石出溶有钠长石,钠长石在正长石晶体内定向 ...