精华内容
下载资源
问答
  • Flutter & Dart 全栈开发 三端⼀一体化编程的新⽅方式
  • 全栈Dart 构建全栈Dart Web应用程序
  • Flutter全栈式开发之Dart 编程指南

    千次阅读 2020-02-13 20:59:25
    开发者可以通过 Dart语言开发 App,一套代码可同时运行在 iOS 、Android、Mac、Windows等平台,甚至能生成Web版,运行于浏览器中。 Dart亮相于2011年10月10至12日在丹麦奥尔胡斯举行的GOTO大会上。该项目由Lars ...

    前言

    Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码可同时运行在 iOS 、Android、Mac、Windows等平台,甚至能生成Web版,运行于浏览器中。

    Dart亮相于2011年10月10至12日在丹麦奥尔胡斯举行的GOTO大会上。该项目由Lars bak和kasper lund创建。2013年11月14日,谷歌正式发布Dart 1.0版本

    Dart 语法结合Java与JavaScript语法特点,几乎没有令人不适的怪异语法,使Java系程序员倍感亲切,快速上手。

    基于目前Flutter的火热,Dart语言也受到重视,但目前缺少一套系统的,细致的Dart编程语言指南,在实践工作中也发现,因为Dart语言没学好,囫囵吞枣式的开始做Flutter开发,一些开发同学极易写出粗糙的代码,或者对语言本身缺乏理解,代码设计不够优雅,Flutter一些源码理解不够深刻(如EventBus、Stream、异步编程等),故录制了一套Dart 编程教程,该套教程着眼于Flutter全栈式,即能熟练运用Dart语言开发Flutter程序,也能使用Dart开发简单的后台服务,编写工具等。

    课程内容

    课程文档:
    在这里插入图片描述
    在这里插入图片描述
    全套Flutter全栈式教程暂定大纲如下,后续会视我个人时间情况,适当增加实战案例。后续Flutter课程的更新情况,受我个人业余时间影响,有快有慢,望理解。
    在这里插入图片描述

    视频课程

    博主发布的相关视频课程

    Flutter全栈式开发之Dart 编程指南
    https://study.163.com/course/courseMain.htm?courseId=1209508814&share=2&shareId=480000001855430
    二维码

    Flutter 全栈式开发指南
    快速上手篇可试看

    欢迎关注我的公众号:编程之路从0到1

    编程之路从0到1

    展开全文
  • 在学习或开发Flutter应用时,很多人会在app中硬编码很多假数据,用以调试界面,实际上我认为是完全没有必要的,Flutter使用Dart语言编程,而Dart语言作为一种全栈语言,其语法可以甩JavaScript几条街,我们是很有...

    在学习或开发Flutter应用时,很多人会在app中硬编码很多假数据,用以调试界面,实际上我认为是完全没有必要的,Flutter使用Dart语言编程,而Dart语言作为一种全栈语言,其语法可以甩JavaScript几条街,我们是很有必要真正的将这种语言的能力发挥出来的。

    这里我就讲讲如何使用Dart语言编写爬虫获取数据,如何使用Dart语言编写编写简单服务器后端。

    Dart 爬虫开发

    首先我们花十分钟来编写一个简易爬虫。

    环境准备

    关于Dart 服务端SDK环境搭建,请阅读我的另一篇文章 Dart语言——45分钟快速入门(上)

    我们完全手动创建一个Dart工程还是略显麻烦,因此我们需要安装一个脚手架,自动生成一个合乎规范的Dart工程项目,执行以下命令安装stagehand

    pub global activate stagehand
    复制代码

    完成安装后直接使用stagehand命令:stagehand -h可能会报找不到错误,这时候我们有两种办法解决

    1. 配置环境变量

      打开cmd命令行,输入如下命令

      echo %APPDATA%\Pub\Cache\bin
      复制代码

      这时可以看到,命令行输出了stagehand命令所在的路径,只需要将该路径加入到系统的Path环境变量即可

    2. 使用pub工具调用

      除了配置环境变量,还可以使用pub global run去调用,由于我本机配置了各种各样的开发语言和工具,命令实在太多,我已经不太喜欢配置环境变量,这里就先使用该方式演示。执行以下命令可以查看一下帮助

      pub global run stagehand -h
      复制代码

    创建工程

    新建一个文件夹spidercd到该目录下,运行以下命令,会在spider下自动生成一个命令行项目

    pub global run stagehand console-full
    复制代码

    使用vscode打开该项目目录

    编辑配置文件pubspec.yaml,避免不必要的下载,删除默认添加的test库依赖,配置如下依赖库

    dependencies:
      http: ^0.12.0+2
      html: ^0.14.0+2
    复制代码

    这里http库主要用于处理http请求,html库用于处理html内容的解析与提取,它们都是Dart官方提供的非标准库,GitHub链接如下

    在项目下执行命令,下载依赖

    pub get
    复制代码

    本文主要做Demo演示,不会对爬虫知识进行讲解。这里主要爬取了一个妹子图网站,大家可以根据自己的实际需要选择目标。如果对爬虫不太了解,请查找资料进行学习,也可以阅读本人的CSDN博客了解爬虫,这里默认大家都掌握爬虫技术。

    我的个人博客

    编辑项目中 lib/spider.dart文件

    import 'package:http/http.dart' as http;
    import 'package:html/parser.dart' show parse;
    import 'package:html/dom.dart';
    import 'dart:convert';
    import 'dart:io';
    
    // 数据实体
    class ItemEntity{
      final String title;
      final String imgUrl;
    
      ItemEntity({this.title,this.imgUrl});
    
      Map<String, dynamic> toJson(){
         return {
            'title': title,
            'imgUrl': imgUrl,
          };
       }
    }
    
    // 构造请求头
    var header = {
      'user-agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) '+
      'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36',
    };
    
    // 数据的请求
    request_data() async{
      var url = "https://www.mzitu.com/";
    
      var response = await http.get(url,headers: header);
      if (response.statusCode == 200) {
        return response.body;
      } 
      return '<html>error! status:${response.statusCode}</html>';
    }
    
    // 数据的解析
    html_parse() async{
      var html = await request_data();
      Document document = parse(html);
      // 这里使用css选择器语法提取数据
      List<Element> images = document.querySelectorAll('#pins > li > a > img');
      List<ItemEntity> data = [];
      if(images.isNotEmpty){
        data = List.generate(images.length, (i){
          return ItemEntity(
            title: images[i].attributes['alt'],
            imgUrl: images[i].attributes['data-original']);
        });
      }
      return data;
    }
    
    // 数据的储存
    void save_data() async{
      var data = await html_parse();
    
      var json_str = json.encode({'items':data});
      // 将json写入文件中
      await File('data.json').writeAsString(json_str,flush: true);
    }
    复制代码

    编辑项目下的 bin/main.dart文件

    import 'package:spider/spider.dart' as spider;
    
    main(List<String> arguments) {
      spider.save_data();
    }
    复制代码

    从篇幅考虑。本文省略数据库相关操作,用一个data.json文件替代。以上代码中save_data函数即处理数据的持久化储存工作,对于小型爬虫而言,推荐使用Sqlite3作为数据库,大型爬虫推荐MongoDB数据库,我个人认为,MongoDB是对爬虫最亲和的数据库。

    运行以上程序,即可生成data.json文件

    总结: 就我个人感觉,使用Dart语言写爬虫肯定是没有Python顺手高效的,Python在爬虫这块的工具过于强大、简洁、高效。

    Dart 服务端

    使用Dart语言的原生API开发HTTP服务器仍显得过于繁琐,因此我们需要一个HTTP服务器框架,这样我们就只需要关注业务逻辑的处理。如果大家使用过任何一款成熟的HTTP服务器框架,那么对于新框架上手就会易如反掌,因为绝大多数服务器框架的概念都是相同的,主要就是ORM、路由映射、模板渲染、中间件等等这些东西。

    根据我所知的,目前可用的仍在维护的Dart的HTTP服务器框架主要有四个,依次按照star最多的从上到下来排序:

    其中排第一的 aqueduct 是功能、文档、示例最完善的,因此我们就以此框架做演示

    安装

    pub global activate aqueduct
    复制代码

    创建项目

    执行命令,生成项目api_server

    pub global run aqueduct create api_server
    复制代码

    最简示例——hello world

    其中bin/main.dart下的入口文件可以不用修改,主要修改lib/channel.dart,删除多余注释,代码如下

    import 'package:api_server/controller.dart';
    
    import 'api_server.dart';
    
    class ApiServerChannel extends ApplicationChannel {
      @override
      Future prepare() async {
        logger.onRecord.listen((rec) => print("$rec ${rec.error ?? ""} ${rec.stackTrace ?? ""}"));
      }
    
      @override
      Controller get entryPoint {
        final router = Router();
        router
          .route("/")
          .linkFunction((request) async {
            return Response.ok('hello world!');
          });
        return router;
      }
    }
    复制代码

    简单说一下,这里有两个实现,其中prepare()方法一般用于预处理,例如连接数据库等,我们暂时用不到,不需理会。entryPoint方法是我们真正需要关注的方法,它的执行在prepare()方法之后,当有请求到来时,就会被回调。我们在该方法中注册路由,这里注册一个根路径,并设置一个响应请求的匿名回调方法。当我们打开浏览器访问http://localhost:8888时,它返回一个响应,即向浏览器打印一句hello world!

    cd到项目根路径下,执行以下命令启动服务

    dart bin/main.dart
    复制代码

    在浏览器访问http://localhost:8888,可以看输出hello world!

    实现后台API服务

    Router除了可以注册回调方法,还可以关联一个Controller用于处理来自客户端的请求。

    在lib目录下新建controller.dart文件,自定义一个Controller。它需要继承自框架的Controller类,并实现一个handle方法。

    import 'dart:async';
    import 'dart:convert';
    import 'dart:io';
    import 'package:aqueduct/aqueduct.dart';
    
    class ItemsController extends Controller {
    
      @override
      Future<RequestOrResponse> handle(Request request) async {
        final content = await File('asset/data.json').readAsString();
        return Response.ok(json.decode(content));
      }
    }
    复制代码

    在项目根路径下新建asset目录,将我们之前爬取的数据文件data.json拷贝进去。然后修改entryPoint方法,再注册一个新的url

      @override
      Controller get entryPoint {
        final router = Router();
        router
          .route("/")
          .linkFunction((request) async {
            return Response.ok('hello world!');
          });
    
    	// 注册一个新的url,并关联到我们自定义的Controller上
        router
        .route('/api/all')
        .link(() => ItemsController());
    
        return router;
      }
    复制代码

    重新启动服务器

    dart bin/main.dart
    复制代码

    浏览器访问http://localhost:8888/api/all,成功获取数据

    创建Flutter项目演示

    Flutter环境准备这里就省略了。先创建一个Flutter 工程用于演示

    代码结构如下

    这里主要是三个文件list_dao.dartitem_model.dartmain.dart

    首先配置依赖文件pubspec.yaml,主要用到了两个库dioflutter_staggered_grid_view

    dependencies:
      flutter:
        sdk: flutter
      cupertino_icons: ^0.1.2
      dio: 2.1.4
      flutter_staggered_grid_view: "^0.2.7"
    复制代码

    下载依赖完成,编辑以下文件 list_dao.dart

    import 'package:flutter_demo/model/item_model.dart';
    import 'package:dio/dio.dart';
    
    class ListDao {
      //这里配置自己的实际域名或IP地址
      static const Host = 'http://192.168.1.102:8888';
      
      static const header = {
        'User-Agent':
            'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0',
        "Referer": "https://www.mzitu.com"
      };
    
      static Future<ItemModel> fetch() async {
        try {
          Response response = await Dio().get("$Host/api/all");
    
          if (response.statusCode == 200) {
            return ItemModel.fromJson(response.data);
          } else {
            throw Exception("StatusCode: ${response.statusCode}");
          }
        } catch (e) {
          print(e);
          return null;
        }
      }
    }
    复制代码

    实体类item_model.dart

    class ItemModel {
      List<Items> items;
    
      ItemModel({this.items});
    
      ItemModel.fromJson(Map<String, dynamic> json) {
        if (json['items'] != null) {
          items = new List<Items>();
          json['items'].forEach((v) {
            items.add(new Items.fromJson(v));
          });
        }
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        if (this.items != null) {
          data['items'] = this.items.map((v) => v.toJson()).toList();
        }
        return data;
      }
    }
    
    class Items {
      String title;
      String imgUrl;
    
      Items({this.title, this.imgUrl});
    
      Items.fromJson(Map<String, dynamic> json) {
        title = json['title'];
        imgUrl = json['imgUrl'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['title'] = this.title;
        data['imgUrl'] = this.imgUrl;
        return data;
      }
    }
    复制代码

    最后就是实际的UI代码了

    import 'package:flutter/material.dart';
    import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
    import 'dao/list_dao.dart';
    import 'model/item_model.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(
            primarySwatch: Colors.pink,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      Future<ItemModel> mFuture;
    
      @override
      void initState() {
        loadData();
        super.initState();
      }
    
      loadData() {
        mFuture = ListDao.fetch();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("美女图"),
          ),
          body: FutureBuilder(
              future: mFuture,
              builder: (ctx, snapshot) {
                switch (snapshot.connectionState) {
                  case ConnectionState.none:
                  case ConnectionState.active:
                  case ConnectionState.waiting:
                    return Center(child: CircularProgressIndicator());
                  case ConnectionState.done:
                    if (snapshot.hasError)
                      return Center(child: Text('Error: ${snapshot.error}'));
                    return _buildList(snapshot.data);
                }
                return null;
              }),
        );
      }
    
      // 创建GridView
      Widget _buildList(ItemModel data) {
        return Container(
          color: Color(0xfff5f6f7),
          padding: EdgeInsets.only(top: 12, left: 10, right: 10),
          child: StaggeredGridView.countBuilder(
            primary: false,
            crossAxisCount: 4,
            itemCount: data?.items == null ? 0 : data.items.length,
            itemBuilder: (ctx, i) {
              return Container(
                decoration: BoxDecoration(
                    color: Colors.white, borderRadius: BorderRadius.circular(8)),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    ClipRRect(		// 处理圆角图片
                        borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(8),
                            topRight: Radius.circular(8)),
                        child: Image.network(data.items[i].imgUrl,
                            headers: ListDao.header)),
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Text(
                        data.items[i].title,
                        style: TextStyle(fontSize: 16),
                      ),
                    )
                  ],
                ),
              );
            },
            staggeredTileBuilder: (int index) => StaggeredTile.fit(2),
            mainAxisSpacing: 10.0,
            crossAxisSpacing: 8.0,
          ),
        );
      }
    }
    复制代码

    确认我们之前写的服务器后端已经启动,然后启动本机模拟器,运行起Flutter App

    总结

    我认为使用Dart语言开发服务端,并结合Nginx用于生成环境下,使Flutter开发人员真正承包整个项目的业务逻辑是非常可行的,这条路才是真正的全栈之路!Dart的语法优势是胜过JavaScript的,即使Java与之相比也显得冗余臃肿。至于是否好用,就待大家自行体会了。

    关于Dart的服务端框架aqueduct,大家有兴趣可以查看官方文档深入学习,本文主要省略了数据库方面的处理,实际上数据库是独立的知识内容,与框架的关系不是太大。而且该框架也提供了一个ORM模块,大家直接查看文档学习 Aqueduct ORM ,但目前似乎只支持PostgreSQL数据库,如果想要使用其他数据库,安装相应的驱动,链接如下

    我的个人博客

    欢迎关注我的公众号:编程之路从0到1

    转载于:https://juejin.im/post/5d051e61e51d4510727c808b

    展开全文
  • 欢迎关注微信公众号:FSA全栈行动 ???? 一、Dart 异步 与 JavaScript 一样, Dart 是基于 事件循环机制 的 单线程模型, 所以 Dart 中没有多线程, 也就没有主线程与子线程之分. 1、同步与异步 同步: 同一线程中, ...

    欢迎关注微信公众号:FSA全栈行动 👋

    一、Dart 异步

    与 JavaScript 一样, Dart 是基于 事件循环机制单线程模型, 所以 Dart 中没有多线程, 也就没有主线程与子线程之分.

    1、同步与异步

    • 同步: 同一线程中, 按照代码的编写顺序, 自上而下依次执行 (直观感受: 需要等待)
    • 异步: 代码执行中, 某段代码的执行不会影响后面代码的执行 (直观感受: 无需等待)

    2、单线程模型

    单线程模型:

    • 一条执行线上, 同时且只能执行一个任务(事件), 其他任务都必须在后面排队等待被执行.
    • 为了不阻碍代码的执行, 每遇到的耗时任务都会被挂起放入任务队列, 待执行结束后再按放入顺序依次执行队列上的任务, 从而达到异步效果.

    单线程模型 与 多线程 各自的优势:

    • 单线程模型的优势: 避免了多线程的缺点, 比较适合于需要等待对方传送数据或返回结果的耗时操作, 如网络请求, IO 操作等.
    • 多线程的优势: 尽可能利用处理器的多核实现并行计算的计算密集型操作.

    多线程 的缺点:

    • 会带来额外的资源和性能消耗.
    • 多个线程操作共享内存时需要加锁控制, 锁竞争会降低性能和效率, 复杂情况下还容易造成死锁.

    3、事件循环机制

    对于用户点击, 滑动, 硬盘 IO 访问等事件, 你不知道何时发生或以什么顺序发生, 所以得有一个永不停歇且不能阻塞的循环来等待处理这些 “突发” 事件. 于是, 基于 事件循环机制单线程模型 就出现了:

    Dart 事件循环机制由 一个消息循环(Event Looper) 和 两个消息队列(Event Queue) 构成, 这两个消息队列分别是: 事件队列(Event queue)微任务队列(MicroTask queue).

    Event Looper

    Dart 在执行完 main 函数后, Event Looper 就开始工作, Event Looper 优先全部执行完 Microtask Queue 中的 event, 直到 Microtask Queue 为空时, 才会执行 Event Looper 中的 event, Event Looper 为空时才可以退出循环.

    注意: Event Looper 为空时, 是 可以 而不是 一定 要退出, 视场景而定.

    Event Queue

    Event Queue 的 event 来源于 外部事件Future

    • 外部事件: 例如输入/输出, 手势, 绘制, 计时器, Stream 等
    • Future: 用于自定义 Event Queue 事件

    对于外部事件, 一旦没有任何 microtask 要执行, Event loop才会考虑 event queue中的第一项,并且将会执行它.

    通过 Future 实例向 Event Queue 添加事件:

    Future(() {
      // 事件任务
    });
    

    Microtask Queue

    • Microtask Queue 的优先级高于 Event Queue.
    • 使用场景: 想要在稍后完成一些任务(microtask) 但又希望在执行下一个事件(event)之前执行.

    Microtask 一般用于非常短的内部异步动作, 并且任务量非常少, 如果微任务非常多, 就会造成 Event Queue 排不上队, 会阻塞 Event Queue 的执行(如: 用户点击没有反应). 所以, 大多数情况下优先考虑使用 Event Queue, 整个 Flutter 源代码仅引用 scheduleMicroTask() 方法 7 次.

    通过 scheduleMicroTask() 函数向 Microtask Queue 添加任务:

    scheduleMicrotask(() {
      // 微任务
    });
    

    二、Future

    Dart 中的异步操作主要使用 Futureasync/await, 整体与前端 ES6 中的 Promise, async/await 的使用差不多, 可以把 Future 理解为是一个自带 callback 效果的类.

    1、基本使用

    通过查看 Future 的构造函数知道, 创建时需要传入一个返回值类型是 FutureOr<T> 的函数:

    factory Future(FutureOr<T> computation()) {
      ...
    }
    

    这个 FutureOr<T> 是一个联合类型, 最终类型可能是 Future 或是泛型 T 的具体类型. 当不指定泛型 T 时, 实例类型为 Future<dynamic>. 下面是一个模拟网络耗时请求的例子:

    Future<String> getNetworkData() {
      // 1. 将耗时操作包裹到Future的回调函数中
      return Future<String>(() {
        sleep(Duration(seconds: 2));
    
        return "Hello lqr"; // 只要有返回结果, 那么就执行Future对应的then的回调(相当于Promise-resolve)
        // throw Exception("error"); // 如果没有结果返回(有错误信息), 需要在Future回调中抛出一个异常(相当于Promise-reject)
      });
    }
    

    Future 实例有 3 个常用方法:

    • then((value){…}): 正常运行时执行
    • catchError((err){…}): 出现错误时执行
    • whenComplete((){…}): 不管成功与否都会执行

    通过以上 3 个方法, 即可获得 Future 实例的执行状况与结果:

    main(List<String> args) {
      print("main start");
    
      // 2. 拿到结果
      var future = getNetworkData();
      future.then((value) => print(value)) // Hello lqr
          .catchError((err) => print(err))
          .whenComplete(() => print("执行完成")); // 不管成功与否都会执行
    
      print("main end");
    }
    

    日志输出如下:

    main start
    main end
    
    // 2秒后输出:
    Hello lqr
    执行完成
    

    注意, 以上 3 个方法是可以分开写的, 但每次执行完一个方法时需要对 future 实例重新赋值(相当于包了一层), 否则后续方法无效:

    var future = getNetworkData();
    
    // 错误写法:
    future.then((value) => print(value));
    future.catchError((error) => print(error)); // 无效
    
    // 正确写法:
    future = future.then((value) {
      print(value);
      return value;
    });
    future.catchError((error) => print(error)); // 有效
    

    2、链式调用

    Future 可以在 then()方法中返回另一个 Future 实例, 从而达到链式调用的效果, 这对那些有数据关联的网络请求很有用:

    main(List<String> args) {
      print("main start");
    
      // 链式调用, 执行多个数据处理
      Future(() {
        return "第一次结果";
      }).then((value) {
        print(value);
        return "第二次结果";
      }).then((value) {
        print(value);
        return "第三次结果";
      }).then((value) {
        print(value);
      }).catchError((error) {
        print(error);
      });
    
      print("main end");
    }
    

    强调: Future 构造函数要求传入一个返回值类型是 FutureOr<T> 的函数, 但因为 FutureOr<T> 是联合类型, 所以, 这里可以返回另一个 Future 实例, 或者是一个具体类型数据, 比如字符串.

    3、其它 API

    Future 除了默认构造器外, 还提供了几个常用的命名构造器:

    • Future.value(): 创建一个返回具体数据的 Future 实例
    • Future.error(): 创建一个返回错误的 Future 实例
    • Future.delayed(): 创建一个延时执行的 Future 实例
    main(List<String> args) {
      print("main start");
    
      Future.value("Hello lqr").then((value) => print(value));
    
      Future.error("出错了").catchError((error) => print(error));
    
      Future.delayed(Duration(seconds: 3))
          .then((value) => "Hello lqr")
          .then((value) => print(value));
    
      Future.delayed(Duration(seconds: 2), () => "Hello lqr")
          .then((value) => print("welcome"))
          .then((value) => throw Exception("出错了"))
          .catchError((error) => print(error))
          .whenComplete(() => print("执行完成")); // 不管成功与否都会执行
    
      print("main end");
    }
    

    三、async/await

    async/await 是 Dart 提供的可以用 同步的代码格式 实现 异步的调用过程语法糖.

    1、基本使用

    • await 必须在 async 函数中使用
    • async 函数返回的结果必须是一个 Future
    Future getNetworkData() async {
      var userId = await getUserId();
      var userInfo = await getUserInfo(userId);
      return userInfo.username // 会自动包裹成Future
    }
    

    如果不使用 async/await, 那么上面的代码则需要这么写:

    Future getNetworkData() {
      return getUserId().then((userId) {
        return getUserInfo(userId);
      }).then((userInfo) {
        return userInfo.username;
      });
    }
    

    相比之下, 使用 async/await 写出来的代码在理解上会更加清晰.

    四、isolate

    所有的 Dart 代码都是在 isolate 中运行的, 它就是机器上的一个小空间, 具有自己的私有内存块和一个运行着 Event Looper 的单个线程. 每个 isolate 都是相互隔离的, 并不像线程那样可以共享内存. 一般情况下, 一个 Dart 应用只会在一个 isolate 中运行所有代码, 但如果有特殊需要, 可以开启多个:

    注意: Dart 中没有线程的概念, 只有 isolate .

    1、创建 isolate (Dart API)

    Dart 默认提供了 Isolate.spawn(entryPoint, message) 用于开启 isolate, 通过源码可以知道形参 message 其实是 形参 entryPoint 对应的函数执行时需要的参数:

    external static Future<Isolate> spawn<T>(
        void entryPoint(T message), T message,
        {bool paused = false,
        bool errorsAreFatal = true,
        SendPort? onExit,
        SendPort? onError,
        @Since("2.3") String? debugName});
    

    使用 Isolate.spawn(entryPoint, message) 开启 isolate, 并指定要执行的任务:

    import 'dart:isolate';
    
    main(List<String> args) {
      print("main start");
    
      Isolate.spawn(calc, 100);
    
      print("main end");
    }
    
    void calc(int count) {
      var total = 0;
      for (var i = 0; i < count; i++) {
        total += i;
      }
      print(total);
    }
    

    2、isolate 通信 (单向)

    isolate 间可以一起工作的唯一方法是通过来回传递消息. 一般情况下, 子isolate 会将运行结果通过管道以消息的形式发送到 主isolate, 并在 主isolateEvent Looper 中处理该消息, 这时就需要借助 ReceivePort 来处理消息的传递了:

    • 在启动 子isolate 时, 将 主isolate 的发送管道(SendPort)作为参数传递给 子isolate.
    • 子isolate 在执行完毕时, 可以利用管道(SendPort)给 主isolate 发送信息.
    import 'dart:isolate';
    
    main(List<String> args) async {
      print("main start");
    
      // 1. 创建管道
      var receivePort = ReceivePort();
    
      // 2. 创建isolate
      Isolate isolate = await Isolate.spawn(foo, receivePort.sendPort);
    
      // 3. 监听管道
      receivePort.listen((message) {
        print(message);
        // 不再使用时, 关闭管道
        receivePort.close();
        // 不再使用时, 将 isolate 杀死
        isolate.kill();
      });
    
      print("main end");
    }
    
    void foo(SendPort sendPort) {
      sendPort.send("Hello lqr");
    }
    

    以上只实现了 isolate 的单向通信, 双向通信比较麻烦, 有兴趣可以再查看一些其他资料.

    3、创建 isolate (Flutter API)

    Flutter 提供了更为方便的开启 isolate 的 API: compute() 函数. 以下是示例代码:

    main(List<String> args) async {
      int result = await compute(powerNum, 5);
      print(result);
    }
    
    int powerNum(int num) {
      return num * num;
    }
    

    compute() 是 Flutter 的 API, 不是 Dart 的 API, 所以, 上面的代码只能在 Flutter 项目中才能运行.

    参考资料

    展开全文
  • 全栈Dart 一个使用Dart语言开发所有应用程序层的示例。 该实验的目的还在于找到一种方法,通过应用有趣的架构模式来共享最大的逻辑。 服务器(API) GRPC规格 该服务器完全基于和。 基本上,此技术使您可以通过专用...
  • Dart语言的前世今生

    2019-12-27 15:30:50
    Dart语言将是您必须掌握的一门语言,因为他将是成为统一前端与后端的全栈语言。各位程序员朋友可要小心了,现在三个岗位的工作,未来可能只需要一个人了。 一、该不该学习Dart语言? 如果你在2018年问这个问题,...

    写在最前面(时间紧的朋友看第一段即可)

    Dart语言将是您必须掌握的一门语言,因为他将是成为统一前端与后端的全栈语言。各位程序员朋友可要小心了,现在三个岗位的工作,未来可能只需要一个人了。

    一、该不该学习Dart语言?

    如果你在2018年问这个问题,收到答案肯定是不应该学,因为2018年Dart被评为了最不应该学习语言的榜首。如果您在2019年,我建议学习Dart,因为Dart被评为2019年开发者最希望学习的榜首。

    2018 和2019为何出现如此截然相反的态度呢,原因很简单其亲爹谷歌已经将其册封为太子,而且还为其娶了一个叫Flutter的太子妃,未来新一代操作系统fuchsia将以Dart为主力语言。而且谷歌最赚钱的Adwords广告业务已经采用Dart进行开发。站在巨人肩膀上的Dart肯定能够成为未来的主流语言。

    二、Dart使命是什么?

    我们通过Dart语言的成长历史,来发掘一下Dart的历史使命

    1. Dart语言的诞生

    2011年10月10日,Google 发布了Dart语言,文章的标题为《Dart: A language for structured web programming》(Dart:结构化的Web编程语言)。下面是Dart语言的设计目标:

    • 为web开发创建一个结构化并且灵活的语言

    • Dart让开发者感觉亲切友好并且容易学习

    • 确保Dart语言在所有新型浏览器和服务器上都保持更高的执行性能,并且能够在支持从智能手持设备到服务端开发工作。

    Dart具有非常广泛的应用场景,其即支持一个人简单的项目还支持大型项目的开发工作。Dart团队认为该语言将成为开发大型Web的伟大语言。

    https://blog.chromium.org/2011/10/dart-language-for-structured.html

    从上面介绍我们可以看出,Dart语言是一个开发web应用的语言,其主要是为了创建大型web应用而发明的。

    2. 第一个正式稳定的版本

    2013年11月14日,谷歌发布Dart 1.0版本,其标题为《Dart 1.0: A stable SDK for structured web apps》(Dart 1.0:一个稳定的web应用结构开发SDK)

    Dart 1.0版本发布,不但推出了Dart语言1.0版本而且还推出了相关开源工具箱和配套的编辑器。还介绍了已经有Blossom, Montage, Soundtrap, Mandrill, 谷歌内部 CRM 应用 and Google Elections等应用使用Dart进行了开发。

    https://news.dartlang.org/2013/11/dart-10-stable-sdk-for-structured-web.html

    3. Dart 2.0 重生的版本

    2018年8月8日,谷歌发布Dart2.0版本,其标题为《Announcing Dart 2 Stable and the Dart Web Platform》(Dart2 稳定版本和Dart Web平台发布)

    此次更新,可谓是让Dart浴火重生。从13至18年,Dart不问不火,特别是其运行效率成为了被人诟病的槽点。2018年谷歌对Dart进行全新改版,从底层重构了Dart语言,加入了很多面向未来的新特别,语言性能大幅提供。此次发布谷歌不仅发布了Dart 2.0稳定版,而且还重写了Dart web platform。新版的web platform 提供了一套高性能、可扩展的生产力工具。

    Dart 2 终点聚焦下面三个方面:功能不断加强和越来越严谨的语言;同时支持web和移动客户端开发;丰富工具箱和组件,全面融合谷歌全家桶。

    https://medium.com/dartlang/dart-2-stable-and-the-dart-web-platform-3775d5f8eac7

    4. Flutter 发布

    2018年12月4日,谷歌发布Flutter 1.0版本,其标题为《Flutter 1.0: Google’s Portable UI Toolkit》(Flutter 1.0:谷歌的可移植UI工具箱)

    Flutter是谷歌开源的移动应用开发SDK,使用Flutter 可以直接开发Android和iOS应用。其最大的特点就是一套代码多平台运行、高性能和Hot Reload(热重载)。谷歌即将发布Fuchsia系统就以Flutter为主要开发框架。Flutter采用Dart作为其底层语言。Dart也由于Flutter美好未来而得到众多开发者的青睐。

    https://developers.googleblog.com/2018/12/flutter-10-googles-portable-ui-toolkit.html

    三、关于Dart的传说

    关于Dart传说有多种,一种为Dart是未来的Javascript,另外一种是Dart未来的Java。

    1. 未来的Javascript

    引自 《Dart in Action》 第18页

    2011年9月,网络上出现了一封标题为“未来的JavaScript”的谷歌内部电子邮件,邮件中表明由于Javascript语言发展缓慢,因此谷歌打算设计一个更好的web开发语言。这种新语言旨在成为下一代的JavaScript。它的主要目标是“保持JavaScript的动态特性,但具有更好的性能配置文件,并且适合大型项目的工具。”它还能够交叉编译为JavaScript。这种语言作为技术预览发布给更广泛的世界,并命名为Dart。

    JavaScript可谓是前端开发的王者,然而其在面向对象方面的薄弱让无数人诟病。由于其设计之初的缺陷,开发者社区一种呼吁进行修改,因此谷歌推出了一门新的开发语言来取代Javascript。另外Dart语言设计者Lars Bak也是V8 JavaScript engine开发者,可见Dart与Javascript传言不假。

    2. 未来的Java

    Java是Sun公司的伟大发明,不过很可惜Sun后来被Oracle收购后,Java是否收费问题影响了其发展。作为Sun公司的同名师兄弟Google成为了Java发展的幕后英雄,Android系统的推出让Java再次焕发了青春。不过进入2018年后,Oracle开始在Java授权方面蠢蠢欲动,Google也因此下定决心设计一个新的面向对象语言(下一代Java)。另外Dart 语言设计者Lars Bak 就是jvm发明者,从此点可以看出Dart肯定是有Java的基因。

    3. Javascript 和 Java的传说

    Java 和 Javascript从名称上看肯定是有一定渊源,翻看Javascript历史可以发现Javascript和Java的关系果真不简单。

    1995年在网景公司工作的Brendan Eich在设计一款在浏览器上运行的编程语言,某位高级主管要求他该语言要遵守Java的语法规范,Brendan Eich不得不接受这个要求,他用了10天就完成新语言的设计工作。

    写在最后

    因此融合“Javascript 传说”和“Java传传说”,我们发现一个秘密,Dart 未来不仅仅是Java或者Javascript,其野心可能是要统一前后端开发,成为一个真正的全栈语言。各位程序员朋友可要小心了,现在三个岗位的工作,未来可能只需要一个人了


     

    展开全文
  • 工作上的需要,被迫上线学习Flutter,看了下文档和线上的专栏,人老了...然而nodejs的出现,JavaScript很快覆盖了全栈,很多手机应用和桌面应用也成为了JavaScript的宿主容器。这使Dart始终不温不火,这么多年来内置Da
  • Flutter和Cloud Run的全栈演示 这是使用和构建的全栈应用程序的演示。 前端是一个桌面Flutter应用程序,该应用程序将您输入的名称发送到后端,然后在快餐栏(用于在页面底部显示消息的临时弹出窗口小部件)中显示...
  • dart是一个新的全栈式语言,主要目标是为了替代js,ts,但是也可以开发app,native的程序。嘛反正现在新语言很多都是全栈的js自己也是所以没什么新奇的,就不多说了。 这一篇主要说说他的一些语法特性1.强面向对象,...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构建一些应用了。...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构建一些应用了。...
  • Angel是Dart中的全栈Web框架。 它旨在通过以一致的方式提供现成的许多常用功能来简化开发。 具有以下功能,Angel是您应该选择构建下一个项目的多合一框架: GraphQL支持 PostgreSQL ORM 依赖注入 静态文件处理 ...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构建一些应用了。...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢慢尝试着用它来构...
  • Dart语言是谷歌团队开发的一款支持多平台(web、IOS、安卓)的全栈性语言,他也可以在前端,后端,服务器端上进行各种开发应用,是个不错的语言,目前也有一些公司在开始慢...
  • 欢迎关注微信公众号:FSA全栈行动 ???? 一、程序入口 一般情况下,Flutter 的主入口是 main.dart。 1、界面的本质(Widget) 在 main 函数中通过 runApp 函数启动一个 Flutter 界面,而 runApp(Widget app) 函数接收...
  • kuasha420-源码

    2021-02-10 11:47:43
    全栈TypeScript开发人员 :telescope: 我目前在担任JavaScript工程师 :seedling: 我目前正在学习Dart&Flutter :star: 您可以找到我的开源项目 我的大多数项目都在 :speech_balloon: 向我询问有关Typescript,...
  • centural_source-源码

    2021-04-17 09:24:10
    第二步从项目的父目录中运行命令dart .\core.dart ,将centural_datapack /基本代码导入ObjD层,然后编译出位于centural_datapack / centural内部的最终数据包。 该导入过程将与一起设计,以正确地对代码进行代码...
  • 第二步从项目的父目录中运行命令dart .\core.dart ,将centural_datapack /基本代码导入ObjD层,然后编译出位于centural_datapack / centural内部的最终数据包。 该导入过程将与一起设计,以正确地对代码进行代码...
  • 我的目标是成为一名出色的全栈Web开发人员。 如果您有一些资源要共享,请这样做。 我渴望找到新的东西并学习。 培训班 Dart+颤振 Docker + Kubernetes 计算机科学与算法 长生不老药 - **** 高朗 - Ruby Ruby ...
  • :eyes: 我对全栈移动应用程序DeskTOP应用程序和Web应用程序开发感兴趣。 .I Love to coding using problem solving :revolving_hearts: JAVA - C# - DART - JAVASCRIPT - PHP - C++ . - 移动开发技术-颤振-...
  • 了解移动端合适的常见难点,学习Dart语法,掌握控件,布局,动画,操作手势,传感器,线程网络以及交互等核心技能。 标题 细节 节点开发 掌握Node项目部署,发布流程,打通全栈,完成产品的自主研发上线。 麻省...
  • 创建该代码库的目的是演示使用构建的完整的全栈应用程序,其中包括CRUD操作,身份验证,路由,分页等。 我们竭尽全力遵守社区的风格指南和最佳实践。 有关如何与其他前端/后端一起使用的更多信息,请转至库。 怎么...
  • Announcing Dart 2.12 JavaScript Library to work against complex domain names, subdomains and URIs. Javascript Virtual Keyboard - Customizable, responsive and lightweight Deno 1.8 Release Notes 第九...
  • Growth: 全栈增长工程师指南 返回目录 Android Android Design(中文版) Google Material Design 正體中文版 (译本一 译本二) Material Design 中文版 Google Android官方培训课程中文版 Android学习之路 Android...

空空如也

空空如也

1 2
收藏数 33
精华内容 13
关键字:

dart全栈