dart入门

  • Dart是Google发布的一门开源编程语言

  • Dart是面向对象的、类定义的、单继承的语言。

变量声明

  • var

    类似于JavaScript中的var,它可以接收任何类型的变量,但最大的不同是Dart中var变量一旦赋值,类型便会确定,则不能再改变其类型。之所以有此差异是因为Dart本身是一个强类型语言,任何变量都是有确定类型的,在Dart中,当用var声明一个变量后,Dart在编译时会根据第一次赋值数据的类型来推断其类型,编译结束后其类型就已经被确定,而JavaScript是纯粹的弱类型脚本语言,var只是变量的声明方式而已。

  • dynamic / Object

    Dynamic和Object 与 var功能相似,都会在赋值时自动进行类型推断,不同在于,赋值后可以改变其类型。Object 是dart所有对象的根基类,也就是说所有类型都是Object的子类,所以任何类型的数据都可以赋值给Object声明的对象,所以表现效果和dynamic相似。

  • final / const

    如果从未打算更改一个变量,那么使用 final 或 const,不是var,也不是一个类型。 一个 final 变量只能被设置一次,两者区别在于:const 变量是一个编译时常量,final变量在第一次使用时被初始化。被final或者const修饰的变量,变量类型可以省略。

函数

Dart是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征。

  1. 函数声明

    dart函数声明如果没有显示申明返回值类型时会默认当做dynamic处理,注意,函数返回值没有类型推断。

  2. 对于只包含一个表达式的函数,可以使用简写语法。也就是箭头函数

  3. 函数作为变量

  4. 函数作为参数传递

  5. 可选的位置参数
    包装一组函数参数,用[]标记为可选的位置参数

  6. 可选的命名参数
    定义函数时,使用{param1, param2, …},用于指定命名参数。调用函数时,可以使用指定命名参数。可选命名参数在Flutter中使用非常多。

异步支持

Dart类库有非常多的返回Future或者Stream对象的函数。 这些函数被称为异步函数:它们只会在设置好一些耗时操作之后返回,比如像 IO操作。而不是等到这个操作完成。

async和await关键词支持了异步编程,运行您写出和同步代码很像的异步代码。

  1. Future

    Future与JavaScript中的Promise非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果,要么成功,要么失败。Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用。

    看一些有关Future的API

    • Future.then

      本例中使用Future.delayed 创建了一个延时任务(实际场景会是一个真正的耗时任务,比如一次网络请求),即2秒后返回结果字符串"hi world!",然后我们在then中接收异步结果并打印结果,代码如下:

      Future.delayed(new Duration(seconds: 2),(){
         return "hi world!";
      }).then((data){
         print(data);
      });
      
    • Future.catchError

      如果异步任务发生错误,我们可以在catchError中捕获错误,我们将上面示例改为:

      Future.delayed(new Duration(seconds: 2),(){
         //return "hi world!";
         throw AssertionError("Error");  
      }).then((data){
         //执行成功会走到这里  
         print("success");
      }).catchError((e){
         //执行失败会走到这里  
         print(e);
      });
      

      在本示例中,在异步任务中抛出了一个异常,then的回调函数将不会被执行,取而代之的是 catchError回调函数将被调用;但是,并不是只有 catchError回调才能捕获错误,then方法还有一个可选参数onError,也可以它来捕获异常:

      Future.delayed(new Duration(seconds: 2), () {
          //return "hi world!";
          throw AssertionError("Error");
      }).then((data) {
          print("success");
      }, onError: (e) {
          print(e);
      });
      
    • Future.whenComplete

      有些时候会遇到无论异步任务执行成功或失败都需要做一些事的场景,比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。这种场景,有两种方法,第一种是分别在then或catch中关闭一下对话框,第二种就是使用Future的whenComplete回调,将上面示例改一下:

      Future.delayed(new Duration(seconds: 2),(){
         //return "hi world!";
         throw AssertionError("Error");
      }).then((data){
         //执行成功会走到这里 
         print(data);
      }).catchError((e){
         //执行失败会走到这里   
         print(e);
      }).whenComplete((){
         //无论成功或失败都会走到这里
      });
      
    • Future.wait

      有些时候需要等待多个异步任务都执行结束后才进行一些操作,比如有一个界面,需要先分别从两个网络接口获取数据,获取成功后,需要将两个接口数据进行特定的处理后再显示到UI界面上,应该怎么做?答案是Future.wait,它接受一个Future数组参数,只有数组中所有Future都执行成功后,才会触发then的成功回调,只要有一个Future执行失败,就会触发错误回调。下面,通过模拟Future.delayed 来模拟两个数据获取的异步任务,等两个异步任务都执行成功时,将两个异步任务的结果拼接打印出来,代码如下:

      Future.wait([
        // 2秒后返回结果  
        Future.delayed(new Duration(seconds: 2), () {
          return "hello";
        }),
        // 4秒后返回结果  
        Future.delayed(new Duration(seconds: 4), () {
          return " world";
        })
      ]).then((results){
        print(results[0]+results[1]);
      }).catchError((e){
        print(e);
      });
      

      执行上面代码,4秒后你会在控制台中看到“hello world”。

Async/await

Dart中的async/await 和JavaScript中的async/await功能和用法是一模一样的。

  • 回调地狱(Callback hell)

    如果代码中有大量异步逻辑,并且出现大量异步任务依赖其它异步任务的结果时,必然会出现Future.then回调中套回调情况。举个例子,比如现在有个需求场景是用户先登录,登录成功后会获得用户Id,然后通过用户Id,再去请求用户个人信息,获取到用户个人信息后,为了使用方便,需要将其缓存在本地文件系统,代码如下:

    //先分别定义各个异步任务
    Future login(String userName, String pwd){
        ...
        //用户登录
    };
    Future getUserInfo(String id){
        ...
        //获取用户信息 
    };
    Future saveUserInfo(String userInfo){
        ...
        // 保存用户信息 
    };
    

    接下来,执行整个任务流:

    login("alice","******").then((id){
     //登录成功后通过,id获取用户信息    
     getUserInfo(id).then((userInfo){
        //获取用户信息后保存 
        saveUserInfo(userInfo).then((){
           //保存用户信息,接下来执行其它操作
            ...
        });
      });
    })
    

    可以感受一下,如果业务逻辑中有大量异步依赖的情况,将会出现上面这种在回调里面套回调的情况,过多的嵌套会导致的代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback hell)。回调地狱问题在之前JavaScript中非常突出,也是JavaScript被吐槽最多的点,但随着ECMAScript6和ECMAScript7标准发布后,这个问题得到了非常好的解决,而解决回调地狱的两大神器正是ECMAScript6引入了Promise,以及ECMAScript7中引入的async/await。 而在Dart中几乎是完全平移了JavaScript中的这两者:Future相当于Promise,而async/await连名字都没改。接下来看看通过Future和async/await如何消除上面示例中的嵌套问题。

    解决方法1

    使用Future消除Callback Hell

    login("alice","******").then((id){
          return getUserInfo(id);
    }).then((userInfo){
        return saveUserInfo(userInfo);
    }).then((e){
       //执行接下来的操作 
    }).catchError((e){
      //错误处理  
      print(e);
    });
    

    “Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用” ,如果在then中返回的是一个Future的话,该future会执行,执行结束后会触发后面的then回调,这样依次向下,就避免了层层嵌套。

    解决方法2

    使用async/await消除callback hell

    通过Future回调中再返回Future的方式虽然能避免层层嵌套,但是还是有一层回调,有没有一种方式能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式?答案是肯定的,这就要使用async/await了,下面我们先直接看代码,然后再解释,代码如下:

    task() async {
       try{
        String id = await login("alice","******");
        String userInfo = await getUserInfo(id);
        await saveUserInfo(userInfo);
        //执行接下来的操作   
       } catch(e){
        //错误处理   
        print(e);   
       }  
    }
    
    • async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用then方法添加回调函数。
    • await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。

    可以看到,我们通过async/await将一个异步流用同步的代码表示出来了。

    无论是在JavaScript还是Dart中,async/await都只是一个语法糖,编译器或解释器最终都会将其转化为一个Promise(Future)的调用链。

你可能感兴趣的:(Flutter)