flutter-Future(async、await)

前言

很多人感觉 flutter 中的 FutureJavaScript 中的 Promise 一样,但是系统介绍却只有一个简单的 async、await使用,实际上他们原理是一样的,使用方法也很相似

async、await实际上就是对 Future 或者 Proimise的一种使用罢了,只不过看起来没有那么明显

Future

Future 与 async、await

我们定义一个方法,来对比一下异步函数的定义,会发现他们两个就是一个东西

//定义两个方法,一个带返回值,一个不带
Future<int> getUserInfo() async {
  print(789);
  return 1;
}

//Future getUserInfo2() async 也和下面一模一样
getUserInfo2() async {
  print(123);
  return 2;
}

//测试方法
testGetUserInfo() {
  final user1 = getUserInfo();
  print(user1);
  final user2 = getUserInfo2();
  print(user2);
}

testGetUserInfo2() async {
  final user1 = await getUserInfo();
  print(user1);
  final user2 = await getUserInfo2();
  print(user2);
}
复制代码

分别代码执行两个测试代码后,返回了下面的结果

//执行testGetUserInfo
789
Instance of 'Future<int>'
123
Instance of 'Future<dynamic>'

//执行testGetUserInfo2
789
1
123
2
复制代码

通过测试结果更加能表明,两个函数默认返回的是一个 Future对象,其中无返回值的函数,返回的是一个泛型为任意类型 dynamicFuture对象

如果采用了 await 之后,此函数会被阻塞执行,直到await里面的执行完毕后,返回结果,才继续往后执行

前面也有提到过,await的函数阻塞后,被放到一个队列中,延迟执行了,毕竟 flutter为单线程模式,Future只是在模拟多线程的操作而已

异步函数的使用

上面了解了 Futureasync 他们的关系之后,这里进一步了解,编写一个异步函数

看了下面代码,会发现,实际上 async 就是封装的一个 Future 函数罢了,返回值为 Future 的 同步函数,因此需要 await 才能达到异步效果(不使用await,就都是同步执行),相信更了解其使用了

//Future其实和js中的 Promise 相似
Future delay1Second() async {
  print("我要沉睡");
  sleep(Duration(seconds: 1));
  print("沉睡完毕");
}
//这个代码实际和上面一样,上面的只是系统自动包装了一个Future而已
Future delay1SecondReplace() {
  return Future(() {
    print("我要沉睡备用");
    sleep(Duration(seconds: 1));
    print("沉睡完毕备用");
  });
}
复制代码

上面的测试结果就不列出来了,和预料一模一样

Future进阶使用

前面提到了 PromiseFuture也能和他一样使用

对于返回类型不是 Future的类型,或者需要加工处理一些异步函数的结果时,难免碰到单纯使用 async、await不太好使的问题,下面就编写一个案例,来演示如何使用

下面有一个方法,是以闭包的方式,异步回调一个结果

//我调用了一个三方,以闭包的方式,异步回调一个结果
threeMethod(Function(int? result) completed) {
  Future.delayed(Duration(seconds: 2), () {
    print("我是一个三方的耗时算法,大约执行2s之后才会有相应");
    //取一个最大为10的随机int整数数
    if (Random().nextInt(10) % 10 > 4) {
      completed(5);
    }else {
      completed(null);
    }
  });
}
复制代码

写过 javascript 的人会很激动,这个我会,一个 Promise + resolve、reject就解决了,例如下面

//Promise版本
workThreeMethod() {
  return Promise((resolve, reject) => {
    threeMethod((res) {
      //对方执行完毕后的回调,返回null就是计算出错了,这里给外面一个error
      if (res == null) {
        //也可以不返回error,只有completed,那样就是外面不用catch了
        reject(new Error("计算出错了,返回一个错误,需要外面catch一下"));
      }else {
        resolve(5);
      }
    })
  });
}
复制代码

可是,Future,中没有 resolve、reject怎么办?

系统提供了 Completer 类,如下所示,会发现,除了多引出一个对象,太相似了

workThreeMethod() {
  //如果不想往外传值,泛型就改成void,否则使用指定类型,或者不填(不填默认为dynamic)
  final completer = Completer<int>();
  threeMethod((res) {
    //对方执行完毕后的回调,返回null就是计算出错了,这里给外面一个error
    if (res == null) {
      //也可以不返回error,只有completed,那样就是外面不用catch了
      //await时会报错,报crash,外面需要.catch
      completer.completeError("计算出错了,返回一个错误,需要外面catch一下");
    }else {
      //回到结果,await的就是这里回调的结果
      completer.complete(5);
    }
  });
  return completer.future;//最后返回一个future
}
复制代码

下面就是正确的调用场景,对于有错误的

//有回调错误的一般这么写
testWorkThreeMethod() {
  workThreeMethod().then((res) {
    print('res:${res}');
  }).catchError((err) {
    print('err:' + err);
  });
}

//也可以这么写,这样函数本来的错误,也会到这里
testWorkThreeMethod2() async {
  try {
    final res = await workThreeMethod();
    print(res);
  }catch(err) {
    print(err);
  }  
}
复制代码

如下所示,可以看到两个执行结果一样

我是一个三方的耗时算法,大约执行2s之后才会有相应
err:计算出错了,返回一个错误,需要外面catch一下

我是一个三方的耗时算法,大约执行2s之后才会有相应
计算出错了,返回一个错误,需要外面catch一下
复制代码

ps:第二个除了捕获到自己的completeError,还能捕获到自己代码的error

最后

Future 原理上和 Promise一样,其他语言如果也有类似的,那么可以尝试一下是否原理一致,类似的东西可以串起来

另外 Promise中的 AllFuture中也有哈

例如: Future 中的 any,参数为 Future数组,返回也是一个 Future,结果为数组类型

看完,是不是感觉很简单呢,快来试试吧

猜你喜欢

转载自juejin.im/post/7074571685734645768