概述

m2.df2.app并不是从df1进行直接升级,两者因为所依赖的核心框架的不同而有较大差异,

  1. 与df1.app完全不同,更类似与PC端开发框架df2.pc, 整合最新Ionic4,完全遵循Angular最佳实践。其中框架部分更加独立方便更新,提供更多扩展部分。
  2. CSS部分更加尊重Ionic4自身扩展建议,更轻量化、扩展Css部分名称更加标准化,与Bootstrap命名规范兼容。
  3. 同时支持App、Wechat、Dingtalk开发,但是三者开发有很大不同,为了减少相互干扰造成框架的复杂性,尽量以独立插件方式提供,后台服务也同步升级,逻辑拆分更加清楚。
  4. df2.app 依赖最新的Angular8、Rxjs6和Ionic4,需要从官方网站了解其中的变化与不同,其中Rxjs6的变化已经在pc.df2中得到学习。
  5. 与pc端一样,df2.app在封装时参考Angular的官方最佳实践,更加强调“模块化”的思路;请开发时遵守框架的相关约定。
  6. df2.app开始M2DF系列将开始开发脚手架项目,以简化框架在项目中使用的复杂性,脚手架采用原理图开发,具体参照angular官方原理图

    df2.app的初始化与脚手架

    创建项目
  7. ionic start your_project https://github.com/jacobqd/m2-df2-app

  8. cd your_project
  9. 修改package.json文件中项目描述
  10. 使用命令 ng i @jzhsoft/m2-df2-scaffold , 安装m2.df2的脚手架 ,脚手架使用官方原理图开发,参照angular官方原理图

    1. "name": "m2app-df2",
    2. "version": "0.9.0",
    3. "author": "m2 dev",
    4. "homepage": "https://www.m2plat.com",

    df2.app的脚手架

    df2.app可以用于app、wechat、dingtalk等应用的开发,但是他们的依赖、启动方式、守卫模式还有native的相关内容不尽相同,所以df2.app采用插件化开发的尝试,并为此开发了一套脚手架系统,便于开发人员在初始化框架。
    脚手架开发使用angular官方推荐的原理图进行开发,已经推送到npm库中

  11. 开发APP,需要全局安装ionic@5.2.3cordova@8.1.2,如果需要生成res需要安装cordova-res@latest,如果需要连接真机调试,还需要安装native-run@latest

    1. ng g m2-df2-scaffold:app //安装相关框架核心文件,将框架改变为适合native开发,同时注入native相关的实现类
    2. npm i //安装app开发所需要的依赖
    3. ionic cordova platform add android/ios // 安装cordova插件
  • 开发微信公众号

    1. ng g m2-df2-scaffold:wx ,会安装wechat开发所需要的依赖,js文件,相关框架核心文件
    2. npm i
    3. 修改df-ext里面的运行模式为:RUNMODE.WECHAT
  • 开发钉钉微应用

    1. ng g m2-df2-scaffold:dd ,会安装dingtalk开发所需要的依赖,js文件,相关框架核心文件
    2. npm i
    3. 修改df-ext里面的运行模式为:RUNMODE.DINGTALK

    注意插件安装是互斥的,不要同时安装,因为每个插件包中都包含接口的本类型实现

    项目结构

    df2的最大特点就是应用了angluar的最佳实践,在最大程度上实现各功能之间的解耦和独立,这一点,您将在下面的阐述中发现:

  1. 框架全部文件在 app/df目录下,这里面的内容一般情况下不需要做任何修改,它与外面您的项目几乎没有耦合,所以您可以在以后任意时刻重新覆盖这个文件夹,以实现框架的升级。
  2. app/df-ext,这个文件夹提供给框架菜单扩展、覆盖、路由扩展等等内容。
  3. environments,这个文件夹支持了多开发环境变量的配置,配合angular.json可以实现各环境的轻松切换,所以原来的constants文件也不需要关注和配置了。
  4. app/df/common,这个文件夹保持与df1的一致,但是需要了解的是虽然位置一致,很多内容的使用方式已经改变了,但是大部分内容都不需要开发人员关心,除非您也对df2进行二次开发。包括组件,指令,管道,拦截器等等。
  5. app/df/core,这个文件夹名称上是df2的核心部分,但是它的实现并不多,从angular的最佳实践中可以了解到, 仅只留 providers 属性。作用: 一些通用服务,例如:用户消息、HTTP数据访问。Constants文件被移动到这里(这个移动没有其他含义,只是从字面意思上放在这里更加合理),这里定义的连接后端的地址和其他各种控制常量,菜单文件也在这里。但是它们已经不再需要您修改这些文件了,你只需要在df-ext中进行配置即可。
  6. app/df/layout,这个文件夹是布局部分,它将为Tab模式、Menu模式、微信模式、钉钉模式提供不同布局
  7. app/df/plugin,这个文件夹是新增的插件部分,将会与M2DF2的脚手架程序配合,以实现不同的开发模式
  8. app/df/guard,这个文件夹是新增的守卫部分,因为新的Ionic4完全采用了Angular的路由实现,守卫的应用将会成为重点
  9. app/df/models,基础Model的封装,例如请求model和返回model
  10. app/df/share,共享模块,简化共同组件、管道等内容的引入,注意服务不能在放在这里,为什么?

原来的constants常量文件已经去掉了,由df-ext中的AppData代替

关于拦截器

AIN和X-Token是后端对身份验证令牌,X-Token用于识别您的身份,AIN用于识别您来自哪一类型的终端,因为我们后端可以支持pc,app,微信,钉钉,很有必要区分同一个用户能够访问那些业务系统。
df2默认会全局处理掉0,401,500等已知错误类型,向下级订阅者抛出异常。
df2默认30000毫秒的请求超时判断,如果后台或网络延迟较为严重,请注意放大该参数。请求超时后,会向下游订阅者抛出{error: string}类型的err,可以进行判断完成其他业务处理,也可以不加任何处理。

路由变化与DF2中路由结构(重点)

如果从df1.app升级上来,那么路由模块是变化最大的部分,ionic4官方表述:
传统的网络应用程序使用线性历史记录,这意味着用户可以向前导航到某个页面,并可以点击后退按钮进行导航。这方面的一个例子是点击维基百科,用户在浏览器的线性历史堆栈上前进和后退。
相比之下,移动应用程序通常使用并行的“非线性”导航。例如,选项卡式界面可以为每个选项卡分别设置导航堆栈,确保用户在导航和切换选项卡时不会失去位置。
Ionic4应用程序采用这种移动导航方法,支持也可以嵌套的并行导航历史,同时保持Web开发人员熟悉的熟悉的浏览器式导航概念。
对于使用Angular构建的应用程序@ionic/angular,我们建议使用开箱即用的Angular Router,用于每个新的Ionic 4 Angular应用程序。Ionic的早期版本附带了我们自己的定制路由器,但为了提供最佳的工具和开发人员体验,我们已经转向使用框架推荐的路由器。
离子如何处理页面的寿命
Ionic的路由器插座称为<ion-router-outlet />。该插座扩展了Angular的<router-outlet />一些附加功能,以为移动设备提供更好的体验。
打包应用后<ion-router-outlet />,Ionic对导航的处理会有所不同。当您导航到新页面时,Ionic会将旧页面保留在现有DOM中,但是将其从视图中隐藏并转换新页面。我们这样做的原因有两个:

  • 1)我们可以维护旧页面的状态(屏幕上的数据,滚动位置等。)
  • 2)我们可以提供更平滑的过渡到页面,因为它已经存在并且不需要重新创建。

仅在“弹出”页面时才将页面从DOM中删除,例如,通过按下UI中的“后退”按钮或浏览器的“后退”按钮。
由于这种特殊的处理方式,通常您认为应该触发ngOnInitand ngOnDestroy方法。
ngOnInit只会在每次重新创建页面时触发,而在导航回该页面时不会触发。例如,在选项卡界面中的每个页面之间导航只会调用每个页面的ngOnInit方法一次,而不会在以后的访问中调用。ngOnDestroy仅在“弹出”页面时触发
每种生命周期方法的指南
以下是有关每个生命周期事件的用例的一些提示。

  • ngOnInit -初始化组件并从不需要在每次后续访问中刷新的服务中加载数据。
  • ionViewWillEnter-由于ionViewWillEnter每次浏览视图时都会调用(无论是否初始化),因此这是从服务加载数据的好方法。但是,如果您的数据在动画过程中返回,则可能会启动许多DOM操作,这可能会导致某些不稳定的动画。
  • ionViewDidEnter-如果ionViewWillEnter在加载数据时发现使用时出现性能问题,则可以ionViewDidEnter改为进行数据调用。但是,只有在用户看到页面之后,该事件才会触发,因此您可能要使用加载指示器或框架屏幕,因此在过渡完成后内容不会自然闪烁。
  • ionViewWillLeave-可用于清除,例如取消订阅可观察对象。由于ngOnDestroy从当前页面导航时可能不会触发,因此如果您不希望在屏幕不可见时不激活清除代码,请在此处放置清除代码。
  • ionViewDidLeave -触发此事件时,您知道新页面已完全过渡,因此可以在可见视图中执行通常不执行的任何逻辑。
  • ngOnDestroy-清除您不想在其中清除的页面的逻辑ionViewWillLeave。

为什么还保留了菜单?
如果菜单与路由是一对一的关系,并且层次也是一致的话,没有必要定义菜单数据,可以直接使用router的data属性来定义路由的静态数据。但是在实际项目中往往同一路由地址会被映射到多个菜单位置,甚至一个菜单对应一个以上复杂的路由情形(比如多个路由出口),更普遍的是层级不同。为了支持app能够使用menu模式而保留的菜单?
路由守卫
在DF2.app中路由守卫缺省使用了canActivate,而不是canActivateChild,两者之间的差别需要注意!主要是因为canActivateChild被执行更多的次数,而app中往往不需要我们对每级路径变化都要进行守卫,所以使用canActivate更加适合。

  • 路由器守卫现在可以返回一个UrlTree。这允许警卫取消当前导航并重定向到由此表示的URL UrlTree。
  • 现在有一个“守卫优先权”的概念,当多个警卫UrlTree在单个导航期间返回时,它被用作打破平局。
  • 添加了一个用于runGuardsAndResolvers被调用的新配置选项pathParamsChange

df2中预置了几个常用守卫,其中authGuard拦截验证的基础,moduleImportGuard守卫模块不要被重复引入,loginGuard来守卫login页面不被history.back()所再次进入。另外在各个平台的plugin中也提供与平台相关的守卫,比如wechatGuard是配合微信公众号使用的拦截验证守卫,等等
预加载策略
在ionic4的开发中,开发的业务模块全部采用懒加载方式,但是如果你在开发者模式下查看网络,会发现所有懒加载模块都被“急性加载”了,你可能会认为我们框架的懒加载并没有起作用,其实不然,因为框架在路由配置时,预加载策略使用的是PreloadAllModules,如果项目的实际场景不需要预加载惰性模块,请修改配置项。官方说法:PreloadAllModules适用于大多数开发情形,如果项目过于庞大,不要使用此策略,可以使用更加复杂的加载策略,或者df2后期开发自己的加载策略。预加载策略是未来优化系统的一个重点部分,策略的好坏可能较大影响系统的速度体验。
惰性模块的划分建议
在实际开发中,发现开发人员不会考虑如何划分惰性模块,或者是惰性模块的颗粒度大小如何划分,而是直接将每一个功能都写成惰性模块,这也是一个不好的习惯!我们知道一次网络请求的开销,有很多是浪费在DNS解析、路由、协议握手等节点,如果过多的网络请求会有大量的开销浪费。比如,1次请求一个2M的文件,就不如分5次按需加载400K左右的文件;但是如果是一个500K的文件,你分100次请求每次5K的,和1次请求一个500K的哪个时间会长一些呢?相信不用测试直觉都能回答!

df2启动引导过程与高级钩子

df2启动过程比以往任何都要快的多,这是得益于df2将大量的启动执行代码按照应该的加载顺序放置到不同启动阶段(也可以称之为钩子),与angular和ionic的加载过程并行加载。对比以往,df1是将框架加载过程放在appComponent的构造或init方法中,虽然没有错误,但是几乎与angluar和ionic加载是顺序执行,相对感觉启动速度较慢。如此处理带来了复杂性,需要做好代码分解,异步执行的完成等待要协调一致,还好这一切都是df2内部的事情,如果不涉及到对df2进行改动,可以不用去理解。
df2启动代码分布大致如下:
核心模块forRoot → 各插件forRoot → 各模块构造 → APP_INITIALIZER → ngDoBootstrap → 启动组件构造 → APP_BOOTSTRAP_LISTENER → initializeProject
项目初始化钩子
df2预置了一个项目级别的启动钩子initializeProject,开发者如果需要在启动阶段初始化一些代码可以在此钩子中运行,它运行在启动组件的onInit方法之后,所以它执行时机足够晚基本上df2启动准备完毕了

  1. // 这个钩子函数是提供项目自己的初始化,会在AppComponent的OnInit之后运行
  2. async initializeProject() {
  3. M2Logger2.log("initializeProject钩子开始执行……");
  4. try {
  5. await this.platform.ready();
  6. await this.m2plat.ready();
  7. // 项目中自己的初始化代码开始
  8. M2Logger2.log("项目中初始化的代码开始执行……");
  9. // 项目的初始化代码结束
  10. } catch (e) {
  11. this.m2Toast.presentWarningToast(e).then();
  12. }
  13. }

启动组件
启动组件不一定是AppComponent,df2采用的运行时指定加载组件的方式,也就是说项目如果需要可以用其他组件来替换AppComponent来实现一些特殊需求效果。为了保证上面的钩子有效,其他组件实现一下BootstrapComponent这个接口export class AppComponent implements OnInit, BootstrapComponent {}就可以了。
甚至于AppModule不一定是启动模块……

ionic中angular变更检查的不同

DOM渲染时机不同
ionic作者非常引以自豪的就是他在ionic中优化DOM渲染方式,更加高效。但是却有意无意之间影响到了angular的变更检查,会造成我们理解上的困惑。请不要尝试用angular官方变更检查周期的描述来理解ionic。 高效Dom写入

布局颠簸可能会导致问题。即使单个重漆或回流很快进行,如果我们通过不断触发大量重新涂漆和回流来锤击我们的应用,则会产生明显的性能影响。这可以通过进行DOM更新以响应滚动等事件而变得特别明显,其中许多事件不断被触发,而不是仅通过单击按钮单击事件。 高效的DOM写入 重绘和重排是不可避免的(如果我们希望浏览器更新页面),但它们可以进行优化。可以做的一个重大改进是批量生成DOM更新,而不是只是随时更新DOM。如果你想5个更新到DOM,而不是做一个在时间和造成重绘和回流对所有的人,你可以做所有5一次,并只需要对付一个回流或重新绘制。

虚竹的话:Ionic提供DomController来应对“布局颠簸”,其实angular本身就有解决方案,结合ngZone来实现,df2.app上有一个代码实例
简单描述Angular变更检测周期
运行Angular应用程序是一个组件树。在更改检测期间,Angular会对每个组件执行检查,其中包括按指定顺序执行的以下操作:

  1. 更新所有子组件/指令的绑定属性
  2. 调用ngOnInit,OnChanges并ngDoCheck在所有的子组件/指令周期挂钩
  3. 更新当前组件的DOM
  4. 运行子组件的更改检测
  5. ngAfterViewInit为所有子组件/指令调用生命周期钩子

在每次操作之后,Angular会记住它用于执行操作的值。它们存储在oldValues组件视图的属性中。在对所有组件Angular进行检查之后,然后开始下一个摘要周期,但不是执行上面列出的操作,而是将当前值与它从前一个摘要周期记住的值进行比较:

  1. 检查传递给子组件的值是否与用于立即更新这些组件的属性的值相同
  2. 检查用于更新DOM元素的值是否与现在用于更新这些元素的值相同
  3. 对所有子组件执行相同的检查

臭名昭著的ExpressionChangedAfterItHasBeenCheckedErrorAngular
stackoverflow上典型问题。通常会出现这些问题,因为Angular开发人员不了解变更检测的工作原理以及为什么需要进行产生此错误的检查。许多开发人员甚至将其视为一个错误。但肯定不是。这是一种警示机制,用于防止模型数据和UI之间的不一致,从而不会向页面上的用户显示错误或旧数据。
JS的回调处理
我们现在可以熟练的引入纯js库来完成一些功能,而无需TS包装,例如微信的jssdk,自开发cordova(没有进行type包装),那么我们就会遇到一个问题,在回调中赋值并没有绑定到界面上,这是为什么呢?于是大家可能ChangeDetectorRef的detectChanges方法来强制一次变更检查,这可以解决问题的方法之一,更加合理的方法应该是 this.m2Utils.zoneRun(你的函数)()来包裹运行,zoneRun是一个高阶函数,它的返回还是你的最初函数,但是它的外层包裹了一段代码可以判断当前是否在变更检查区域,如果不在会强制ngZone.run中来保证变更检查能够顺利执行。完整的代码在下面:

  1. // 获取地理位置
  2. getLocation() {
  3. this.m2wx.ready("http://f.199.m2platform.cn/m2/lab/wechat/poi-demo").then(() => {
  4. wx.getLocation({
  5. type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  6. success: res => {
  7. this.m2Utils.zoneRun(() => {
  8. this.text = `经度:${res.longitude}, 纬度:${res.latitude}`;
  9. })();
  10. },
  11. cancel : function(res) {
  12. console.log("cancel: " + res);
  13. }
  14. });
  15. });
  16. }

df2.app四端统一API

此部分会持续更新,注意关注;四端统一API是指浏览器端、APP端(Android和IOS)、微信端和钉钉端开发都需要用到,但是由于平台不同调用方式不同,df2.app 中将尝试将此部分内容统一封装,以简化学习和开发时间成本,例如获取定位,浏览器上用js函数,app中用cordova插件,微信和钉钉有各自的jsapi,在框架中希望能用统一的调用方法
平台信息Api

关于webview

ionic webview
  1. This plugin uses WKWebView on iOS and the latest evergreen webview on Android. Additionally, this plugin makes it easy to use HTML5 style routing that web developers expect for building single-page apps.

在df2.app中需要注意一点,在插件安装时,指定的时ionic-webview4.x,与以前的版本区别很大,请阅读官方文档。例如在IOS中,Apps are now served from ionic:// scheme on iOS by default,那么后端的跨域请求限制需求相应调整。

禁用angular净化机制

如果引用一个本地图片,按照官方说法“he WebView is not able to display images, videos or other files from file or content protocols or if it doesn’t have protocol at all. For those cases use window.Ionic.WebView.convertFileSrc() to get the proper url.” 但是如果直接将转化的值双向绑定到img src中,那么有可能会触发Angular的值净化机制, Angular中DomSanitizer 可以把值净化为在不同 DOM 上下文中的安全内容,来帮你防范跨站脚本攻击(XSS)类的安全问题,应该通过bypassSecurityTrustUrl() 绕过安全检查,并信任给定的值是一个安全的样式 URL。也就是说该值可安全地用在链接或 <img src> 中。框架中M2Utils中fixURL(),已经给出了实现。

真机运行环境配置

ionic官方给了native-run,首先全局安装,npm i -g native-run;安卓环境,建议使用android studio进行配置比较傻瓜式,然后下载sdk,安装ADB,创建一个模拟器,在命令行中运行adb devices可以检查手机连接是否正常。命令ionic cordova run android -l —configuration=dev4 可以进行真机测试,并开启liveload。
同样IOS需要在mac上安装最新xcode,运行命令ionic cordova emulate ios —livereload —configuration=dev4
以上ionic命令默认使用native-run,上述命令都测试通过。如果要使用cordova提供的真机测试,需要增加参数—no-native-run。
####Angular Ivy (常春藤)
df2.app中开启了Ivy渲染引擎,开发者本身无需过多关注,可能需要简单了解,遇到问题后如何关闭

df2.app覆盖的知识点

差分加载

df2.app框架默认配置了差分加载,为了利用高版本angular提供新特性,以获得更小的bundle包和更快的运行速度,事实上还是要关注这项新技术的适应性,比如微信开发者工具中:
在构建 Web 应用时,确保你的应用与大多数浏览器兼容是目标之一。JavaScript 在不断发展,新功能不断推出,不是所有浏览器都能以同样的进度实现这些新功能。这就是编译和腻子脚本(polyfill)的用武之地。你在开发过程中使用 TypeScript 编写的代码会被编译并打包成一种兼容大多数浏览器的格式,通常为 ES5。 腻子脚本用于抹平差距,提供一些老式浏览器中根本不存在的功能。
确保这种浏览器的兼容性是有代价的,那就是更大的包体积。所有现代浏览器都支持 ES2015 及更高版本,但在大多数情况下,你仍然要考虑那些从老式浏览器访问你的应用的用户。为了最大限度地提高兼容性,你需要发布一个包含所有已编译代码的发布包(bundle),以及所有可能会用到的腻子脚本。用户如果在支持大量最新 JavaScript 特性的现代浏览器中使用此应用,他就不应该为这些额外的包体积付出启动时间和流量等方面的代价。这就是差异化加载发挥作用的地方。
差异化加载是指 CLI 在构建应用时,构建两个单独发布包的策略。现代的发布包中包含了现代的语法,利用了现代浏览器的内置支持,减少了腻子脚本的运行需求,减小了发布包的大小。第二个发布包中则包含了额外的编译代码,所有必需的腻子脚本,并导致了更大的包大小。这个策略允许你继续构建你的 Web 应用来支持多个浏览器,但是只加载相应浏览器中必需的代码。

Shadow DOM(影子DOM)

顾名思义, shadow-dom,直译的话就是 影子dom ?我觉得可以理解为潜藏在黑暗中的 DOM 结构,也就是我们无法直接控制操纵的 DOM 结构。shadow-dom 其实是浏览器的一种能力,它允许在浏览器渲染文档(document)的时候向其中的 Dom 结构中插入一棵 DOM 元素子树,但是特殊的是,这棵子树(shadow-dom)并不在主 DOM 树中。
影响多大?
基于目前(2019年09月18日更新)的对ionic4的了解,ionic4 大部分独立组件都采用了shadowDom的方式进行了封装;这样使ionic前端style部分的接口样式变的解耦的更彻底、样式冲突基本不会存在,而开发人员不能再使用css 元素选择器 随意的更改ionic封装好的组件样式,必须采用官方暴露的配置变量的写法更改组件的样式,具体可参阅ionic4相关组件文档

解构分配

解构赋值语法是一个 Javascript 表达式,这使得可以将值从数组或属性从对象提取到不同的变量中。
简单举例: var {op, lhs, rhs} = getASTNode()
详细了解参考 CSDN例子 博客园 解构嵌套对象

==和===

== equality 等同,=== identity 恒等。 ==, 两边值类型不同的时候,要先进行类型转换,再比较。 ===,不做类型转换,类型不同的一定不等。
先说 ===,这个比较简单。下面的规则用来判断两个值是否===相等:
1、如果类型不同,就[不相等]
2、如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断)
3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
4、如果两个值都是true,或者都是false,那么[相等]。
5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
6、如果两个值都是null,或者都是undefined,那么[相等]。
再说 ==,根据以下规则:
1、如果两个值类型相同,进行 === 比较。
2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:

  • a、如果一个是null、一个是undefined,那么[相等]。
  • b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
  • c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
  • d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。非js核心的对象,令说(比较麻烦,我也不大懂)
  • e、任何其他组合,都[不相等]。

    async-await 函数

    ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖。在前面的项目中发现部分出现此类代码,可能来源是参考了别人的代码进来的,没有考虑到项目的编译情况,有可能存在滥用的情况。df2.app将正式建议使用此语法糖。
  1. await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中。
  2. 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
  3. await命令只能用在async函数之中,如果用在普通函数,就会报错。
    toPromise()
    开发过程中发现很多代码并不理解其中含义,而只是简单的copy使用,例如将Observable使用toPromise操作符,看下面的解释:

    The toPromise function is actually a bit tricky, as it’s not really an “operator”, rather it’s an RxJS-specific means of subscribing to an Observable and wrap it in a promise. The promise will resolve to the last emitted value of the Observable once the Observable completes. That means that if the Observable emits the value “hi” then waits 10 seconds before it completes, the returned promise will wait 10 seconds before resolving “hi”. If the Observable never completes, then the Promise never resolves.

如何优化异步绑定

我们在开发过程中,经常会遇到从后台返回数据然后绑定到界面上的场景。在该场景中后台数据返回目前都是采用观察者对象,在绑定数据时,一般有两种处理方式,
一:采用异步管道,如何写,例如,user$对象 界面上应该是
{{ (user | async).name}}
二、声明一个对象并初始化,然后在异步调用时更新这个值,

  1. user = new User();
  2. this.XXXX.subcribe((item) => { this.user = item ;})

你会用哪一种?

可观察对象的多播

典型的可观察对象会为每一个观察者创建一次新的、独立的执行。 当观察者进行订阅时,该可观察对象会连上一个事件处理器,并且向那个观察者发送一些值。当第二个观察者订阅时,这个可观察对象就会连上一个新的事件处理器,并独立执行一次,把这些值发送给第二个可观察对象。
有时候,不应该对每一个订阅者都独立执行一次,你可能会希望每次订阅都得到同一批值 —— 即使是那些你已经发送过的。这在某些情况下有用,比如用来发送 document 上的点击事件的可观察对象。
多播用来让可观察对象在一次执行中同时广播给多个订阅者。借助支持多播的可观察对象,你不必注册多个监听器,而是复用第一个(next)监听器,并且把值发送给各个订阅者。
当创建可观察对象时,你要决定你希望别人怎么用这个对象以及是否对它的值进行多播。