译文 | Angular中的AoT编译
译者:陈旭@中兴RDK
前两天,Jigsaw七巧板上来了个issue https://github.com/rdkmaster/jigsaw/issues/113,@jackjoy 在issue中提到了一篇介绍Angular AoT的文章,我看了一下,觉得讲的非常好,还涉及到一些Angular编译原理的内容。于是打算翻译一下,让大伙都能够读一读,多了解一点AoT知识。
文中的第一人称“我”均指代作者本人(http://blog.mgechev.com)
原文地址是 http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/
最近我给angular-seed增加了对Ahead-of-Time(AoT)编译的支持,这引来了不少关于这个新特性的问题。我们从下面这些话题开始来回答这些问题:
-
为什么Angular需要编译?
-
什么东西会被编译?
-
他们是如何被编译的?
-
编译发生在什么时候?JiT vs AoT
-
我们从AoT中获得了什么?
-
AoT编译是如何工作的?
-
我们使用AoT和JiT的代价是什么?
为什么Angular需要编译?
这个问题的简短回答是:编译可以让Angular应用达到更高层度的运行效率,我所说的效率,主要是指的性能提升,但也包括电池节能和节省流量。
AngularJs1.x 有一个实现渲染和变化检测的很动态的方式,比如AngularJs1.x的编译器非常通用,它被设计为任何模板实现一系列的动态计算,虽然它在通常情况下运行的很好,但是JS虚拟机的动态特性让一些低层次的计算优化变得很困难。由于js虚拟机无法理解那些我们作为脏检查的上下文对象(术语为scope)的形态,虚拟机的内联缓存常常不精确,这导致了运行效率的下降。
译者:scope是AngularJs1.x中的一个重要对象,他是AngularJs1.x用于计算模板的上下文。
Angular2+采用了一个不同的方式。在给每个组件做渲染和变化检测的时候,它不再使用同一套逻辑,框架在运行时或者编译时会生成对js虚拟机友好的代码。这些友好的代码可以让js虚拟机在属性访问的缓存,执行变化检查,进行渲染的逻辑执行的快的多。
举个例子,看看下面的代码:
// ...
Scope.prototype.$digest = function () {'use strict';var dirty, watcher, current, i;do {dirty = false;for (i = 0; i < this.$$watchers.length; i += 1) {watcher = this.$$watchers[i];current = this.$eval(watcher.exp);if (!Utils.equals(watcher.last, current)) {watcher.last = Utils.clone(current);dirty = true;watcher.fn(current);}}} while (dirty);for (i = 0; i < this.$$children.length; i += 1) {this.$$children[i].$digest();}
};
// ...
这个代码片段来自《轻量级angularJs1.x实现》一文。这些代码实现了对scope树做深度优先搜索,目的是为了寻找绑定数据的变化,这个方法对任何指令都生效。这些代码显然比下面这些直接指定检查的代码慢:
// ...
var currVal_6 = this.context.newName;
if (import4.checkBinding(throwOnChange, this._expr_6, currVal_6)) {this._NgModel_5_5.model = currVal_6;if ((changes === null)) {(changes = {});}changes['model'] = new import7.SimpleChange(this._expr_6, currVal_6);this._expr_6 = currVal_6;
}
this.detectContentChildrenChanges(throwOnChange);
// ...
译者:
《轻量级angularJs1.x实现》的地址是 <https://github.com/mgechev/light-angularjs/blob/master/lib/Scope.js#L61-L79
这里一下子提及了angularJs1.x的好几个概念,包括scope,数据绑定,指令。不熟悉angularJs1.x的同学理解起来费劲,想弄懂的话,自行搜索吧。个人认为可以无视,毕竟这个文章的重点不是在这里。你就认为Angular2+的处理方式比angularJs1.x牛逼很多就好了,哈哈。
上面代码包含了一个来自angular-seed的某个编译后的组件的代码,这些代码是由编译器生成的,包含了一个 detectChangesInternal
方法的实现。Angular框架通过直接属性访问的方式读取了数据绑定中的某些值,并且采用了最高效的方式与新的值做比较。一旦Angular框架发现这些值发生了变化,它就立即更新只受这些数据波及的DOM元素。
在回答了“为什么Angular需要编译”这个问题的同时,我们同时也回答了“什么东西会被编译”这个问题。我们希望把组件的模板编译成一个JS类,这些类包含了在绑定的数据中检测变化和渲染UI的逻辑。通过这个方式,我们和潜在的平台解耦了。换句话说,通过对渲染器采取了不同的实现,我们在不对代码做任何的修改的前提下,就可以对同一个以AoT方式编译的组件做不同的渲染。比如,上述代码中的组件还可以直接用在NativeScript中,这是由于这些不同的渲染器都能够理解编译后的组件。
编译发生在什么时候?JiT 还是 AoT
Angular编译器最cool的一点是它可以在页面运行时(例如在用户的浏览器内)启动,也可以作为构建的一个步骤在页面的编译时启动。这主要得益于Angular的可移植性:我们可以在任何的平台的JS虚拟机上运行Angular,所以我们完全可以在浏览器和NodeJs中运行它。
JiT编译模式的流程
一个典型的非AoT应用的开发流程大概是:
-
使用TypeScript开发Angular应用
-
使用
tsc
来编译这个应用的ts代码 -
打包
-
压缩
-
部署
一旦把app部署好了,并且用户在浏览器中打开了这个app,下面这些事情会逐一进行:
-
浏览器下载js代码
-
Angular启动
-
Angular在浏览器中开始JiT编译的过程,例如生成app中各个组件的js代码
-
应用页面得以渲染
AoT编译模式的流程
相对的,使用AoT模式的应用的开发流程是:
-
使用TypeScript开发Angular应用
-
使用
ngc
来编译应用-
使用Angular编译器对模板进行编译,生成TypeScript代码
-
TypesScript代码编译为JavaScript代码
-
-
打包
-
压缩
-
部署
虽然前面的过程稍稍复杂,但是用户这一侧的事情就变简单了:
-
下载所以代码
-
Angular启动
-
应用页面得以渲染
如你所见,第三步被省略掉了,这意味着页面打开更快,用户体验也更好。类似Angular-cli和Angular-seed这样的工具可以让整个编译过程变的非常的自动化。
概括起来,Angular中的Jit和AoT的主要区别是:
-
编译过程发生的时机
-
JiT生成的是JS代码,而AoT生成的是TS代码。这主要是因为JiT是在浏览器中进行的,它完全没必要生成TS代码,而是直接生产了JS代码。
你可以在我的Github账号中找到一个最小的AoT编译demo,链接在这里 https://github.com/mgechev/angular2-ngc-rollup-build
深入AoT编译
这个小节回答了这些问题:
-
AoT编译过程产生了什么文件?
-
这些产生的文件的上下文是什么?
-
如何开发出AoT友好又有良好封装的代码?
对@angular/compiler
的代码一行一行的解释没太大意义,因此我们仅仅来快速过一下编译的过程。如果你对编译器的词法分析过程,解析和生成代码过程等感兴趣,你可以读一读Tobias Bosch的《Angular2编译器》一文,或者它的胶片。
译者:
《Angular2编译器》一文链接 https://www.youtube.com/watch?v=kW9cJsvcsGo
它的胶片链接 https://speakerdeck.com/mgechev/angular-toolset-support?slide=69
Angular模板编译器收到一个组件和它的上下文(可以这认为是组件在组件树上的位置)作为输入,并产生了如下文件:
-
*.ngfactory.ts
我们在说明组件上下文的小节会仔细看看这些文件 -
*.css.shim.ts
样式作用范围被隔离后的css文件,根据组件所设置的ViewEncapsulation
模式不同而会有不同 -
*.metadata.json
当前组件/模块的装饰器元数据信息,这些数据可以被想象成以json格式传递给@Component
@NgModule
装饰器的信息。
*
是一个文件名占位符,例如对于hero.component.ts
这样的组件,编译器生成的文件是 hero.component.ngfactory.ts
, hero.component.css.shim.ts
和 hero.component.metadata.json
。 *.css.shim.ts
和我们讨论的主题关系不大,因此不会对它详细描述。如果你希望多了解 *.metadata.json
文件,你可以看看“AoT和第三方模块”小节。
*.ngfactory.ts
的内部结构
它包含了如下的定义:
-
_View_{COMPONENT}_Host{COUNTER}
我们称之为internal host component -
_View_{COMPONENT}{COUNTER}
我们称之为 internal component
以及下面两个函数
-
viewFactory_{COMPONENT}_Host{COUNTER}
-
viewFactory_{COMPONENT}{COUNTER}
其中的 {COMPONENT}
是组件的控制器名字,而 {COUNTER}
是一个无符号整数。他们都继承了 AppView
,并且实现了下面的方法:
-
createInternal
组件的渲染器 -
destroyInternal
执行事件监听器等的清理 -
detectChangesInternal
以内联缓存优化后的逻辑执行变化检测
上述这些工厂函数只在生成的AppView
实例中才存在。
我前面说过,detectChangesInternal
中的代码是JS虚拟机友好的。
<div>{{newName}}</div>
<input type="text" [(ngModel)]="newName">
我们来看看编译后这个模板的代码,detectChangesInternal
方法的代码看起来像是这样的:
// ...
var currVal_6 = this.context.newName;
if (import4.checkBinding(throwOnChange, this._expr_6, currVal_6)) {this._NgModel_5_5.model = currVal_6;if ((changes === null)) {(changes = {});}changes['model'] = new import7.SimpleChange(this._expr_6, currVal_6);this._expr_6 = currVal_6;
}
this.detectContentChildrenChanges(throwOnChange);
// ...
假设currVal_6
的值是3, this_expr_6
的值是1,我们来跟踪看看这个方法的执行。对于这样的一个调用 import4.checkBinding(1, 3)
,在生产环境下, checkBinding
执行的是下面的检查:
1 === 3 || typeof 1 === 'number' && typeof 3 === 'number' && isNaN(1) && isNaN(3);
上述表达式返回false
,因此我们将把变化保持下来,以及直接更新 NgModel
的属性 model
的值,在这之后,detectContentChildrenChanges
方法会被调用,它将为整个模板内容的子级调用 detectChangesInternal
。一旦 NgModel
指令发现了 model
属性发生了变化,它就会(几乎)直接调用渲染器来更新对应的DOM元素。
目前为止,我们还没有碰到任何特殊的,或者特别复杂的逻辑。
context
属性
也许你已经注意到了在internal component内部访问了 this.context
属性。
译者:internal component 指的前一小节的
_View_{COMPONENT}{COUNTER}
函数
internal component中的 context
是这个组件的控制器的实例,例如这样的一个组件:
@Component({selector: 'hero-app',template: '<h1>{{ hero.name }}</h1>'
})
class HeroComponent {hero: Hero;
}
this.context
就是 new HeroComponent()
,这意味着如果在 detectChangesInternal
中我们需要访问 this.context.name
的话,就带来了一个问题:如果我们使用AoT模式编译组件的模板,由于这个模式会生成TypeScript代码,因此我们要确保在组件的模板中只访问 this.context
中的public成员。这是为何?由于TypeScript的类属性有访问控制,强制类外部只能访问类(及其父类)中的public成员,因此在internal component内部我们无法访问 this.context
的任何私有成员。因此,下面这个组件:
@Component({selector: 'hero-app',template: '<h1>{{ hero.name }}</h1>'
})
class HeroComponent {private hero: Hero;
}
以及这个组件
class Hero {private name: string;
}@Component({selector: 'hero-app',template: '<h1>{{ hero.name }}</h1>'
})
class HeroComponent {hero: Hero;
}
在生成出来的 *.ngfactory.ts
中,都会抛出编译错误。第一个组件代码,internal component无法访问到在 HeroComponent
类中被声明为 private 的 hero
属性。第二个组件代码中,internal component无法访问到 hero.name
属性,因为它在 Hero
类中被声明为private。
AoT与封装
好吧,我们只能在组件模板中绑定public属性,以及调用public方法。但是,如何确保组件的封装性?在开始的时候,这可能不是一个大问题,但是想象一下下面这个场景:
// component.ts
@Component({selector: 'third-party',template: `{{ _initials }}`
})
class ThirdPartyComponent {private _initials: string;private _name: string;@Input()set name(name: string) {if (name) {this._initials = name.split(' ').map(n => n[0]).join('. ') + '.';this._name = name;}}
}
这个组件有一个属性 name
,它只能写入而无法读取。在 name
属性的 setter 方法中,计算了 _initials
属性的值。
我们可以用类似下面的方式使用这个组件:
@Component({template: '<third-party [name]="name"></third-party>'// ...
})
// ...
在JiT编译模式下,一切正常,因为JiT模式只生成JavaScript代码。每次 name
属性的值发生变化,_initials
就会被重新计算。但是,这个组件却不是AoT友好的,必须改为:
// component.ts
@Component({selector: 'third-party',template: `{{ initials }}`
})
class ThirdPartyComponent {initials: string;private _name: string;@Input()set name(name: string) {...}
}
codelyzer 这个工具可以确保你在模板中每次都能访问到public成员。
这让组件的使用者可以这样做:
import {ThirdPartyComponent} from 'third-party-lib';@Component({template: '<third-party [name]="name"></third-party>'// ...
})
class Consumer {@ViewChild(ThirdPartyComponent) cmp: ThirdPartyComponent;name = 'Foo Bar';ngAfterViewInit() {this.cmp.initials = 'M. D.';}
}
对public属性 initials
的直接修改导致了组件处于不一致性的状态:组件的 _name
的值是 Foo Bar
,但是它的 initials
的值是 M. D.
,而非 F. B.
。
在Angular的源码中,我们可以找到解决的办法,使用TypeScript的 /** @internal */
注释声明,就能够达到既保证组件代码对AoT友好,又能够确保组件的封装良好的目的。
// component.ts
@Component({selector: 'third-party',template: `{{ initials }}`
})
class ThirdPartyComponent {/** @internal */initials: string;private _name: string;@Input()set name(name: string) {...}
}
initials
属性仍然是public的。我们在使用 tsc
编译这个组件时,设置 --stripInternal
和 --declarations
参数,initials
属性就会从组件的类型定义文件(即 .d.ts
文件)中被删掉。这样我们就可以做到在我们的类库内部使用它,但是我们的组件使用者无法使用它。
ngfactory.ts
概要
我们来对幕后所发生的一切做一些概要描述。拿我们前面的例子中的 HeroComponent
为例,Angular编译器会生成两个类:
-
_View_HeroComponent_Host1
这是 internal host component -
_View_HeroComponent1
这是 internal component
_View_HeroComponent1
负责渲染这个组件的模板,以及进行变化检测。在执行变化检测时,它会对 this.context.hero.name
之前保存的值和当前值做比较,一旦发现这两个值不一致, <h1/>
元素就会被更新,这意味着我们必须保持 this.context.hero
和 hero.name
是public的。这一点可以通过 codelyzer 这个工具来辅助确保。
另外,_View_HeroComponent_Host1
则负责 <hero-app></hero-app>
和 _View_HeroComponent1
本身的渲染。
这个例子可以以下面这个图来总结:
AoT vs JiT 开发体验
这个小结,我们来讨论使用AoT开发和JiT开发的另一种体验。
可能使用JiT对开发体验的冲击最大的就是JiT模式为internal component和internal host component生成的是JavaScript代码,这意味着组件的控制器中的属性都是public的,因此我们不会得到任何编译错误。
在JiT模式下,一旦我们启动了应用,根组件的根注入器和所有的指令就已经准备就绪了(他们被包含在 BrowserModule
和其他所有我们在根模块中引入的模块中了)。元数据信息会传递给编译器,用于对根组件的模板的编译。一旦编译器生成了JiT下的代码,编译器就拥有了用于生成各个子组件的所有元数据信息。由于编译器此时不仅知道了当前层级的组件有那些provider可用,还可以知道那些指令是可见的,因此它可以给所有的组件生成代码。
这一点让编译器在访问了模板中的一个元素时,知道该怎么工作。根据是否有选择器是 bar-baz
的指令/组件,<bar-baz></bar-baz>
这样的一个元素就有了两种不同的解释。编译器在创建了 <bar-baz></bar-baz>
这样的一个元素的同时,是否还同时初始化 bar-baz
对应的组件类的实例,则完全取决于当前阶段的编译过程的元数据信息。
这里有一个问题,在编译阶段,我们如何知道指令在整个组件树上是否可访问?得益于Angular框架的良好设计,我们通过静态代码分析就可以做到。Chuck Jazdzewski 和 Alex Eagle 在这个方向上做出了令人惊叹的成果,他们实现了 MetadataCollector
和相关的模块。MetadataCollector
所做的事情就是通过遍历组件树来获取每个组件和NgModule
的元数据信息,这个过程中,很多牛逼的技术被用到,可惜这些技术超出了本文的范畴。
AoT与第三方模块
为了编译组件的模板,编译器需要组件的元数据信息,我们来假设我们的应用使用到了一些第三方组件,Angular的AoT编译器是如何获取这些已经被编译成JavaScript代码的组件的元数据信息的?这些组件库必须连带发布对应的 *.metadata.json
文件,这样才能够对一个引用了它的页面进行AoT编译。
如果你想了解如何使用Angular编译器,例如如何编译你自定义库使得他们能够被用于以AoT编译的应用,那请访问这个链接 https://github.com/angular/mobile-toolkit/blob/master/app-shell/gulpfile.ts#L52-L54
我们从AoT中获得了什么?
你可能已经想到了,AoT给我们带来了性能的提升。以AoT方式开发的Angular应用的初次渲染性能要比JiT的高的多,这是由于JS虚拟机需要的计算量大大减少了。我们只在开发过冲中,将组件的模板编译成js代码,在此之后,用户不需要等待再次编译。
下面这个图中,可以看出JiT渲染方式在初始化过程中所消耗的时间:
下面这个图你可以看出AoT方式初始化在初始化过程中所消耗的时间:
Angular编译器不仅能够生产JavaScript,还能够生成TypeScript,这一点还带给我们要给非常棒的特性:在模板中进行类型检查。
由于应用的模板是纯JavaScript/TypeScript,我们可以精确的知道哪些东西在哪被用到了,这一点让我们可以对代码进行有效的摇树操作,它能够把所有的未使用过的指令/模块从我们生产环境中的应用代码包中给删除掉。这首要的一点是,我们的应用程序代码包中,再也无需包含 @angular/compiler
这个模块,因为我们在应用的运行时根本就用不到它。
有一点需要注意的是,一个中大型的应用代码包,在进行AoT编译过之后,可能会比使用JiT方式编译的代码包要大一些。这是因为 ngc
生成的对JS虚拟机友好的代码比基于HTML模板的代码要冗长一些,并且这些代码还包含了脏检查逻辑。如果你想降低你的应用代码的尺寸,你可以通过懒加载的方式来实现,Angular内建的路由已经支持这一点了。
在某些场合,JiT模式的编译根本就无法进行,这是由于JiT在浏览器中,不仅生成代码,它还使用 eval
来运行它们,浏览器的内容安全策略以及特定的环境不允许这些被生成的代码被动态的运行。
最后一个但不是唯一的:节能!在接受到的是编译后的代码时,用户的设备可以花更少的时间运行他们,这节约了电池的电力。节能的量有多少呢?下面是我做的一些有趣的计算的结果:
基于《Who Killed My Battery: Analyzing Mobile Browser Energy Consumption》这偏文章的结论,访问Wikipedia时,下载和解析jQuery的过程大约需要消耗4焦耳的能量。这个文章没有提及所使用的jQuery的确切版本,基于文章发表的日期,我估计版本号是1.8.x。Wikipedia采用了gzip对静态资源做压缩,这意味着jQuery1.8.3的尺寸约33k。而被最小化并且gzip压缩后的 @angular/compiler
包的尺寸在103k,这意味着对这些代码的下载和解析需要消耗12.5焦的能量(我们可以忽略JiT的运算还会增加能耗的事实,这是因为jQuery和@angular/compiler
这两个场景,都是使用了要给单一的TCP链接,这从是最大的能耗所在)。
iPhone6s的电池容量是6.9Wh,即24840焦。基于AngularJs1.x官网的月访问量可以得知现在大约有一百万名Angular开发者,平均每位开发者构建了5个应用,每个应用每天约100名用户。5个app 1m 100用户 = 500m,在使用JiT编译这些应用,他们就需要下载 @angular/compiler
包,这将给地球带来 500m * 12.5J = 6250000000J焦(=1736.111111111千瓦时)的能量消耗。根据Google搜索结果,1千瓦时约等于12美分,这意味着我们每天需要消耗约 210 美元。注意到我们还没进一步对代码做摇树操作,这可能会让我们的应用程序代码降低至少一半!
结论
Angular的编译器利用了JS虚拟机的内联缓存机制,极大的提升了我们的应用程序的性能。首要的一点是我们把编译过程作为构建应用的一个环节,这不仅解决了非法eval
的问题,还允许我们对代码做高效的摇树,降低了首次渲染的时间。
不在运行时编译是否让我们失去是什么吗?在一些非常极端的场景下,我们会按需生成组件的模板,这就需要我们价值一个未编译的组件,并在浏览器中执行编译的过程,在这样的场景下,我们就需要在我们的应用代码包中包含 @angular/compiler
模块。AoT编译的另一个潜在缺点是,它会造成中大型应用的代码包尺寸变大。由于生成的组件模板的JavaScript代码比组件模板本身的尺寸更大,这就可能造成最终代码包的尺寸更大一些。
总的来说,AoT编译是一个很好的技术,现在它已经被集成到了Angular-seed和angular-cli
中,所以,你今天就可以去使用它了。
参考资料
-
内联缓存 http://mrale.ph/blog/2012/06/03/explaining-js-vms-in-js-inline-caches.html
-
2.5X Smaller Angular 2 Applications with Google Closure Compiler http://blog.mgechev.com/2016/07/21/even-smaller-angular2-applications-closure-tree-shaking/
-
Who Killed My Battery: Analyzing Mobile Browser Energy Consumption https://crypto.stanford.edu/~dabo/pubs/abstracts/browserpower.html
-
Angular的源码 https://github.com/angular/angular
题外话
这些文章都是我们在研发Jigsaw七巧板过程中的技术总结,如果你喜欢这个文章,请帮忙到 Jigsaw七巧板的工程上点个星星鼓励我们一下(点击阅读原文看直达 https://github.com/rdkmaster/jigsaw),这样我们会更有动力写出类似高质量的文章。Jigsaw七巧板现在处于起步阶段,非常需要各位的呵护。
原文发布时间:2017-08-01
本文来源掘金如需转载请紧急联系作者
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 把es6编译成es5
1, 当初解决过程第一步 IE浏览器报Promise未定义的错误 背景: 一个vue-cli构建的vue项目,一个使用angular的项目,两个项目在其他浏览器一切正常,但是ie中会报Promise未定义的错误 解决办法: vue的项目:…...
2024/4/27 14:12:14 - AngularJS权威教程高清版pdf下载
为什么80%的码农都做不了架构师?>>> 高清版带目录下载地址 http://pan.baidu.com/share/link?uk2819121500&shareid741536468&third0&adaptpc&frftw 转载于:https://my.oschina.net/manks/blog/617408...
2024/4/27 9:03:43 - Angular 2 By Example(Angular 2案例电子书免费下载)
下载地址:Angular 2 By Example.pdf 更多免积分电子书,请访问:IE布克斯网 转载于:https://my.oschina.net/u/3070312/blog/2997628...
2024/4/27 14:19:55 - angular高级编程第3版下载_UNIX系统编程宝典,每一本都值得程序员珍藏
这几本UNIX系统编程宝典,重印无数次,几代程序员都视如珍宝的几本书,今天继续分享给你们,好书总会有人还不知道,你说呢?这套书京东在做活动,如需要请自行查看。1、UNIX网络编程 卷1 套…...
2024/4/27 0:55:09 - Angular 2 Components(Angular 2 组件电子书教程免费下载)
Angular 2 组件电子书教程 下载地址:AngularJS Directives Cookbook.pdf 更多Angular电子书、React电子书、Vue.js电子书,请关注我的简书主页。 转载于:https://my.oschina.net/u/3070312/blog/2997596...
2024/4/27 14:57:32 - Angular ionic开发移动端----文件下载*
Angular ionic开发移动端----文件下载 大家好!最近在开发基于angular ionic开的移动端,遇到太多坑了。 一,插件 我这边使用的下载插件是Downloader,在ionic官网Native搜索即可。 首先在node安装 ionic cordova plugin add inte…...
2024/4/27 19:59:55 - angular——导出pdf之滚动后导出不完全
项目场景: 将当前html页面导出成pdf 问题描述: 当滚动条置顶时,导出的pdf没任何问题,但当滚动条出现偏移后,导出的pdf要么内容缺失,要么纯空白页 原因分析: 导出pdf的思路: 步骤…...
2024/4/21 4:27:14 - ng2-pdf-viewer实践
1. 技术架构及版本 Angular 8.2.0ng2-pdf-viewer 5.3.4 2.代码 component import {Component, OnInit} from angular/core;Component({selector: app-doc-preview,templateUrl: ./doc-preview.component.html,styleUrls: [./doc-preview.component.scss] }) export class D…...
2024/4/21 4:27:14 - angular10 html转pdf预览 DomSanitizer安全策略
<iframe [src]="previewNoticePdfUrl" frameborder="0" style="width: 100%; height: 400px"></iframe> 核心代码 this.sanitizer.bypassSecurityTrustResourceUrl(url); import { Component, Input, OnInit } from @angular/core…...
2024/4/21 4:27:13 - Angular4上传和下载
Angular4上传和下载 下载文件 Angular4的单页应用通过Http服务器反向代理后接口的文件流就会放到body中返到客户端,导致浏览器不能识别下载。 下载部分代码如下: Injectable()export class HttpService {constructor(private http: HttpClient,){}//Bl…...
2024/4/21 4:27:12 - angular 手势缩放和在线预览pdf
1.下载这两个插件可以实现在线预览和手势缩放 ng2-pdf-viewer https://www.npmjs.com/package/ng2-pdf-viewer ngx-pinch-zoom https://www.npmjs.com/package/ngx-pinch-zoom 如果出现兼容问题 npm i pdfjs-dist2.4.456...
2024/4/21 4:27:10 - angularjs的双向绑定详解
双向数据绑定可能是AngularJS最实用的特性,将MVC的原理展现地淋漓尽致。 AngularJS的工作原理是: HTML页面的加载,这会触发加载页面包含的所有JS (包括 AngularJS)AngularJS启动,搜寻所有的指令(directive)找到ng-app,搜寻其指定的模块(Mod…...
2024/4/21 4:27:09 - 记一次忏悔的前端面试经验(Vue 双向绑定原理)
2019年6月6号,为了爱情,我离开工作了一年多的广州来到了杭州这个互联网城市。开始我的前端面试之旅...放下拧螺丝的扳手,开始造起了飞机...面试的第一家,一开始就问 Vue 双向绑定怎么实现。一脸蒙蔽,之前看过源码&…...
2024/4/21 4:27:09 - php 双向绑定的原理,Angular和Vue双向数据绑定的实现原理(重点是vue的双向绑定)...
我在整理javascript高级程序设计的笔记的时候看到面向对象设计那章,讲到对象属性分为数据属性和访问器属性,我们平时用的js对象90%以上都只是用到数据属性;我们向来讲解下数据属性和访问器属性到底是什么?数据属性:数据属性包含一个数据值的位置,在这个位置可以读取和写入值.访…...
2024/4/21 4:27:08 - 简单实现 angular1.x 双向数据绑定
angular1.x中双向数据绑定指的是,HTML值变化,与其绑定的js中的变量值也变化,而这都主要依靠angular中$digest完成,无需过多的js代码来实现 <!DOCTYPE html> <html><head><meta charset"utf-8">…...
2024/4/21 4:27:07 - vue双向绑定原理分析
vue双向绑定原理分析 当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理。 简易vue源码地址:https://github.com/jiangzhenfei/simple-Vue 1.vue双向绑定原理 vue.js 则是采用数据劫…...
2024/4/21 4:27:06 - Augular双向绑定原理
angular 转载于:https://www.cnblogs.com/li--xin/p/6951630.html...
2024/4/21 4:27:05 - 双向数据绑定实现原理
vm的核心是view 和 data 当data 有变化的时候它通过Object.defineProperty()方法中的set方法进行监控,并调用在此之前已经定义好data 和view的关系了的回调函数,来通知view进行数据的改变 而view 发生改变则是通过底层的input 事件来进行data…...
2024/4/21 4:27:04 - Angular2中自定义组件实现双向绑定
在Angular2中的数据流动是单向的,我们常见的双向绑定的例子如下: <input [(ngModel)]"value"/> 等价于 <input [ngModel]"value" (ngModelChange)"valueChange($event)"/>那么我们如何实现自定义自己的组件&a…...
2024/4/21 4:27:03 - Angular之双向数据绑定基础
angualrjs比较我所用过的Jquery,确实方便了很多数据的获取,赋值等逻辑简略了很多,也就是说,用很少的代码,就能实现比较复杂的逻辑,话不多少,上例子,今天是用表单来做的,代码如下 in…...
2024/4/21 4:27:01
最新文章
- 必应bing国内广告开户注册教程!
今天搜索引擎广告成为企业推广产品与服务、提升品牌知名度的重要渠道之一。作为全球第二大搜索引擎,必应Bing凭借其高质量的用户群体和广泛的国际覆盖,为广告主提供了独特的市场机遇。在中国,虽然必应的市场份额相对较小,但对于寻…...
2024/4/27 20:14:14 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - audio_video_img图片音视频异步可视化加载
最近在做即时消息,消息类型除了文字还有音频、视频、图片展示,如果消息很多,在切换聊天框时,会有明显卡顿,后续做了懒加载,方案是只加载用户能看到的资源,看不到的先不加载; LazyAud…...
2024/4/27 13:10:31 - 实景三维在数字乡村建设中的重要作用
随着科技的飞速发展,数字乡村建设已成为推动乡村振兴、实现农村现代化的重要途径。实景三维技术作为数字乡村建设的重要支撑,正逐渐在各个领域发挥着不可或缺的作用。本文将从实景三维技术在数字乡村中的应用场景、优势及未来展望等方面进行探讨…...
2024/4/26 0:59:18 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/26 18:09:39 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/26 20:12:18 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/26 23:05:52 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/27 4:00:35 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/26 21:56:58 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/27 9:01:45 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/25 18:39:16 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/26 22:01:59 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/26 23:04:58 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/25 2:10:52 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/25 18:39:00 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/26 19:46:12 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/27 11:43:08 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/27 8:32:30 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57