async-await基本介绍
async-await本质上是对Future API的简化形式,将异步回调代码写成同步代码结构形式。「async关键字修饰的函数总是返回一个Future对象,所以async并不会阻塞当前线程」,由前面的EventLoop和Future我们都知道Future的最终会加入EventQueue中,而EventQueue执行是当main函数执行完毕后,才会检查Microtask Queue和Event Queue并处理它们。「await关键字意味着中断当前代码执行流程直到当前的async方法执行完毕,如果没有执行完毕下面的代码将处于等待的状态」。
为什么需要async-await
通过学习之前异步编程中的Future我们知道,Future一般使用 then
和 catchError
可以很好地处理数据回调和异常回调。这实际上还是一种基于异步回调的方式,如果异步操作依赖关系比较复杂需要编写回调代码比较繁杂,为了简化这些步骤 async-await
关键字通过同步代码结构来实现异步操作,从而使得代码更加简洁和具有可读性,此外在异常处理方式也会变得更加简单。
async await具体使用规则
(1)async的函数在执行后都会自动返回一个Promise对象,有无值根据有无return值。
(2)await必须在async函数里使用,不能单独使用。
(3)await后面需要跟Promise对象,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。
(4)async/await作用是用同步方式,执行异步操作。
generator函数
(1)跟普通函数在写法上的区别就是,多了一个星号*
(2) yield:只有在generator函数中才能使用yield。相当于generator函数执行的中途停站点。
(3)next方法:执行后会返回一个对象,对象中有value和done两个属性。
- value:暂停点后面接的值,也就是yield后面接的值(最后一个是undefined,这取决于generator函数有无返回值)
- done:是否generator函数已走完,没走完为false,走完为true
(4)generator函数可以用next方法来传参,并且可以通过yield来接收这个参数,注意两点
- 第一次next传参是没用的,只有从第二次开始next传参才有用
- next传值时,要记住顺序是,先右边yield,后左边接收参数
function* gen() {
const num1 = yield 1
console.log(num1)
const num2 = yield 2
console.log(num2)
return 3
}
const g = gen()
console.log(g.next()) // { value: 1, done: false }
console.log(g.next(11111))
// 11111
// { value: 2, done: false }
console.log(g.next(22222))
// 22222
// { value: 3, done: true }
原理
Future
是Dart语法异步的核心,通过async
标记一个方法为异步,返回一个future对象,进而对flutter进行监听,获取异步方法的返回值。一般用法为:
Future<int> getCount async {
~~~~
return count;
}
Future<int> future = getCount();
getCount().then((value) {
int res = value;
});
单个异步任务很好理解,代码写起来也很易读,但是多个异步任务协同工作时,这种写法会特别冗余且不易理解,例如:
Future<int> _loadFromDisk(){}
Future<String> _fetchNetworkData(){}
Future<ProcessData> createData() {
return _loadFromDisk().then((id) {
return _fetchNetworkData(id);
}).then((data) {
return ProcessData(data);
})
}
这个方法表示首先调用_loadFromDisk()
方法,获取id后再调用_fetchNetworkData()
方法,获取data后返回ProcessData
,这个是两层嵌套的例子,倘若是3层、4层乃至更多层,代码将杂乱无章。
为了针对这个问题,Dart引入了async
和await
机制,将异步嵌套的代码转换为类似同步代码的结构,极大的方便了编码效率和可读性,上面的两层嵌套等同于:
ProcessData createData() async {
int id = await _loadFromDisk();
String data = await _fetchNetworkData(id)
return ProcessData(data)
}
小结
async
标识一个方法为异步方法,返回的是一个Future
对象,可以监听Future
对象的返回值,也可以用then
的方式等待异步方法执行完毕后继续执行一个方法,若有多个异步方法需要顺序执行,可以采用then
嵌套的方式,但是层数较多时可读性极差,await
可以理解为一个异步的语法糖,通过这种方式可以用类似同步的代码块实现异步方法的顺序执行,可读性很高。
文末
async、await的操作属于"假异步",这是为什么呢? 如果想要得到这个问题的答案,首先我们需要了解async、await的原理,了解协程的概念,因为async、await本质上就是协程的一种语法糖。协程,也叫作coroutine,是一种比线程更小的单元。如果从单元大小来说,基本可以理解为 进程->线程->协程。 更多Flutter线程知识,可前往实战混合式开发Flutter3.0手册进行系统性学习;以及Flutter高级工程师进阶。
网友评论