解密Angular WebWorker Renderer
本文主要介绍Angular中的黑科技之WebWorker Renderer,使用Worker线程渲染如何渲染页面?从源码的角度切入,带领带大家看个究竟。
先来做个对比
开发框架版本:Angular 4.x
项目地址:angular-webworker-renderer-demo
对比对象:传统的UI线程渲染和使用WebWorker线程渲染页面
对比方法:各执行1到1000的连乘,并循环20次,要求实时展示进度
运行结果:
首先是传统的UI线程渲染效果:
其次时使用WebWorker线程渲染效果:
从动图中很明显可以看出,使用了WebWorker Renderer渲染的页面运行流畅,没有卡顿。
简单介绍下Web Woker
Web Workers是一种机制,通过它可以使一个脚本操作在与Web应用程序的主执行线程分离的后台线程中运行。这样做的优点是可以在单独的线程中执行繁琐的处理,让主(通常是UI)线程运行而不被阻塞/减慢。 —— Web Workers API from MDN
简单来说,在出现WebWoker之前,Web开发人员无法手动在浏览器中创建线程,而出现WebWoker之后,Web开发人员可以进入多线程开发Web项目了。
Web Worker的优势
下面根据YouTube视频(见参考)中的内容总结了下使用WebWorker的优势:
- 运行过程中不会阻碍主线程(UI渲染线程)的运行,特别适合执行计算密集型的程序
- WebWorker线程可跨窗口或frames(使用SharedWorker)
- 使用WebWorker后能更优雅地执行测试过程(一些脱离可DOM操作的测试)
- 兼容性(IE 10+)
- 更高效地利用电量
对于最后一点的解释,应该先转化为另外一个问题,一些计算密集型的程序为什么不在服务端执行完毕后返回给前端?这在视频中也给出了解释,作者总结了一句话:It costs more to transmit a byte than to compute it,意思是传输一个byte比计算出一个byte的消耗更大。为什么呢?自己想吧
Web Worker可能的使用场景
那么真的有这么多应用场景吗?以下列举了几个场景:
- 解析一个庞大的JSON结构
- 图片/音频处理
- 大规模数据可视化
仔细想一想,这样的场景还是很特殊的,可能在实际的应用中并不多见。那么,在目前的主流前端框架是否有利用到WebWorker的特性来帮助其提升性能呢?经过调研,发现很多还在探索阶段,比如在React框架中的探索,Parashuram在2016年发布了文章《Using Webworkers to make React faster》,文章是关于如何利用Webworker提升React的渲染速度,主要是把Virtual DOM的相关计算过程(如diff算法)放入WebWorker线程,从结果可以看出,在Benchmark的对比下,使用WebWorker的一方帧率有所提高,感兴趣的同学可以查看其演示示例和项目地址。这里忍不住要引用作者的一张图(如下图所示,纵轴是帧率,横轴是节点的个数),简要展示下React项目在使用WebWorker的情况下,性能的提升效果。
(图片来源:Using Webworkers to make React faster)
那么WebWorker已经面世这么了,浏览器支持也跟上了,为何其应用场景或者与主流框架的结合并没有很多见?我想可能与以下几点WebWorker的缺点相关:
- 在Webworker线程中无法访问DOM节点
- 无法与UI线程共享内存
- 与UI线程通讯的信息需要序列化
- 线程间通讯不可避免的并发问题
虽然如此,Angular背后的Google团队已经开始尝试打破这些限制,并已经在Angular 2.x中得进行了应用(WebWorker Renderer),虽然到了目前的Angular 4.x在源码中仍标识为@experimental,但相信其在将来会成为Angular框架的标配。接下来的文章内容,会分析到在Angular框架中Webworker Renderer是如何工作的,包括如下三个要点:
- 通讯信息如何序列化与反序列化?内存数据如何共享?
- 如何打破Webworker线程不能操作DOM节点的局限?
- 如何处理并发?
希望你能带着这两个问题阅读完以下的篇幅。
先感受一下
图中显示的基本是整个UI线程与WebWorker线程通讯的过程,给你来个初步的影响,可以帮助你在阅读后续内容时有个整体观的把控,图中涉及的类、方法以及过程,在接下来的文章中会一一介绍到。
介绍几个基本的类
先来看看这个RenderStroe类,在Angular是被标识为@Injectable()的可注入类,其中_nextIndex是一个自增的索引号,通过allocateId函数递增分配。store和remove函数是对_lookupById和_lookupByObject两个Map类型的容器进行新增和删除操作,其中的传入的id参数作为唯一的索引号(通过allocateId函数分配而来)。最后deserialize和serialize方法分别是根据id取出内容和根据内容取出id。这意味中在RenderStore中序列化就是将对象转换成一个唯一数字,而相对应的反序列化就是将数字转换为一个对象。
这样一个很重要的RenderStore类就介绍完毕了,它承担了线程间数据信息通讯序列化/反序列化的重要工作。总的来说,就是将需要传输的内容对象与一个索引号对应起来,实现序列化和反序列化的过程。这个类会穿梭于整个工作流程,经常会注入到其他关键类中,是UI线程与WebWorker线程公用的类,两端共同维护同一个副本,间接到达线程间数据共享的目的。
通过这个RenderStore类,我们已经可以解决之前提出第一个问题,放张动图大家先消化消化。聪明的你可能会有以下几个疑问:
- Object对象里存的到底是什么东西?
- 难倒只能由WebWorker线程向UI线程单向地发送同步RenderStore数据的指令?
不慌,我们接下去讲。
这个Serializer类主要用于WebWoker线程与UI主线程之间通讯的时候,提供消息信息序列化和反序列化的操作,其实还是主要依赖于RenderStore提供的方法。
该类定义了序列化的类型,对于string,number,boolean类型,即PRIMITIVE类型,是不需要序列化/反序列化的。通过代码枚举得知,操作支持如下几种类型:
enum SerializerTypes {// RendererType2RENDERER_TYPE_2,// Primitive types,such as string,number,booleanPRIMITIVE,// An object stored in a RenderStoreRENDER_STORE_OBJECT,
}
具体做如下说明(其中只列举了序列化的过程):
- PRIMITIVE类型(原始类型),serializer方法不做任何处理,直接返回;
- Array类型,使用map方法对数组中的每一项再serializer,然后返回;
- RENDER_STORE_OBJECT类型,通过RenderStore类中的serialize方法序列化后返回;
- RENDERER_TYPE_2类型,通过调用_serializeRendererType2方法处理后返回;
- RenderComponentType类型,通过调用_serializeRenderComponentType方法处理后返回;
- LocationType类型,通过调用_serializeLocation方法处理后返回;
其中,RenderComponentType, RendererType2类型是@angular/core中定义的,两者都是Angular编译器中对DOM节点进行渲染处理时定义的类型,这里不多做阐述。LocationType类型是针对浏览器的路由操作(windows.locaion.*)进行的包装,包含href,protocol,host,hostname,port等,容易理解。
此外,serializeRendererType2和serializeRenderComponentType方法体中也是根据序列化对象的结构再进行拆分对待,并继续调用serialize方法处理。比如_serializeRendererType2方法中是这样的:
private _serializeRendererType2(type: RendererType2): {[key: string]: any} {return {'id': type.id,'encapsulation': this.serialize(type.encapsulation),'styles': this.serialize(type.styles),'data': this.serialize(type.data),};
}
从代码中可以看出,通讯信息的序列化/反序列化过程其实就是主要针对string,number,boolean类型(PRIMITIVE类型)和RENDER_STORE_OBJECT类型在作处理,前者不需要序列化/反序列化,后者通过RenderStore提供的方法进行处理。
是时候回答下之前提出的问题:RenderStore中存的Object对象到底是哪些?RENDER_STORE_OBJECT类型是指哪些类型呢?
- WebWorkerRenderer2类型,继承自Renderer2类(该类是Angular的核心类,用于操作DOM相关,这里就不啰嗦了)
- WebWorkerRenderNode类型,该类有且只有一个类型为NamedEventEmitter的成员变量events
于是,不得不提到NamedEventEmitter类,这个类维护了一个Map类型的容器_listener,存储了事件名称和对应的方法,并提供新增(listen)、删除(unliten)以及触发事件的方法(dispatchEvent)。
由此可见,事件的定义、维护和触发在整个线程间通讯过程中至关重要。
再说说与通讯相关的类
根据官方远源码介绍,MessageBus类是一个低级别的API,是一个抽象类,主要用于UI主线程与WebWorker线程的通信相关。而双方的通信是基于通道(channel),通道的两端分别是MessageBusSink(信息流出)和MessageBusSource(信息流入),后续会细说到。类中提及的Zone是Angular的魔法,由于对与本文内容的理解不受影响,因此不做过多阐述,如感兴趣请自行查看。
首先是来列举下Angular中定义的三种通道的类型,三种通道负责不同的工作,分为渲染、事件和路由。
// DOM渲染通道
export declare const RENDERER_2_CHANNEL = "v2.ng-Renderer";
// DOM事件通道
export declare const EVENT_2_CHANNEL = "v2.ng-Events";
// 路由通道
export declare const ROUTER_CHANNEL = "ng-Router";
接下来具体讲下PostMessageBus类,作为MessageBus抽象类的一个实现,类结构如下图所示。
该类的两个公共成员变量分别是source(PostMessageBusSource类型,是MessageBusSource类的一实现类)和sink(PostMessageBusSink类型,是MessageBusSink的实现类),可以解释为水源和水槽。可以这么理解,信息好比是水,可以通过水槽流出,也可以流入到水源中。
类中的initChannel方法对这通道进行初始化,其中有2个的关键点:1)每个通道的实例最多只能有三个不同的通道类型;2)Channel通道信息初始化时候包含了一个EventEmitter类的实例对象,在Sink通道初始化的时候还会对其进行了订阅操作,触发后会执行相应的sendMessage操作,这个发送信息的方法的实现主要是通过该类的构造函数中传入,后面会有所介绍。
另外需要介绍一下PostMessageBusSource类,该类在构造函数中会对Worker对象通过addEventListener方法监听message事件,这个过程能监听信息接收的事件,并且做相应的信息处理的操作,即通过EventEmitter类的emit方法来触发相应的订阅事件。
首先介绍一下WebWorkerRendererFactory2类,从类名中可以解释为WebWorker渲染工厂,在Angular中也被标为@Injectable()类型,其构造函数中依赖ClientMessageBrokerFactory, MessageBus, Serializer, RenderStore类的注入,并对其初始化,如下:
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_2_CHANNEL);
bus.initChannel(EVENT_2_CHANNEL);
const source = bus.from(EVENT_2_CHANNEL);
source.subscribe({next: (message: any) => this._dispatchEvent(message)});
从构造函数中能了解到,主要依赖注入类型的作用,首先通过ClientMessageBrokerFactory创建了通道为RENDERER_2_CHANNEL的代理人,虽然还未具体解释ClientMessageBroker类的作用,但从类命名中就可以了解到它的作用就是作为与UI线程通讯的中间代理人,在该类中负责向UI线程传输DOM节点渲染的工作,这个会在后续会详细介绍。另外,通过自身的MessageBus创建了EVENT_2_CHANNEL通道,并且对信息源做了subscribe的订阅操作,即当UI线程DOM事件触发时,该MessageBus的Source会接收到信息,并触发相应的_dispatchEvent函数操作,在WebWorker层中做相应的处理。
与WebWorkerRendererFactory2对应的就是WebWorkerRenderer2类,该类从类结构中就可以看出包含了各种对DOM节点的操作函数,基本覆盖原生JS的DOM操作函数。特别注意,该类里面的操作函数并不是真正地操作DOM节点,而是在WebWorker线程中的模拟,最后还是以消息的形式发送给UI主线程中调用Renderer2进行操作,后续会讲到。举例说一下其中的createElement函数:
createElement(name: string, namespace?: string): any {const node = this._rendererFactory.allocateNode();this.callUIWithRenderer('createElement', [new FnArg(name),new FnArg(namespace),new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),]);return node;
}
其函数体中的_rendererFactory成员变量是一个WebWorkerRendererFactory2类的实例(在构造函数中传入),调用了allocateNode方法,创建一个包含事件处理的类,再通过RenderStore生成唯一Id,并存储。然后调用callUIWithRenderer函数,如下:
private callUIWithRenderer(fnName: string, fnArgs: FnArg[] = []) {// always pass the renderer as the first argthis._rendererFactory.callUI(fnName, [this.asFnArg, ...fnArgs]);
}
其函数体中的_rendererFactory成员变量是一个WebWorkerRendererFactory2类,调用了callUI方法处理DOM相关的操作函数,包含fnName(方法名)和fnArgns(参数),其中asFnArg是一个默认参数(FnArg类的一个实例),并指定了序列化的类型,因此会被存入RenderStore,定义如下:
private asFnArg = new FnArg(this, SerializerTypes.RENDER_STORE_OBJECT);
那么callUI方法是怎么处理的呢?我们来看一下:
callUI(fnName: string, fnArgs: FnArg[]) {const args = new UiArguments(fnName, fnArgs);this._messageBroker.runOnService(args, null);
}
从函数体中,可以看出调用了ClientMessageBroker的runOnService方法,通过该方法向UI线程发送渲染指令(通过Sink的emit方法)并处理反馈信息,这里先做个简单的介绍,后续会详细介绍。
小小地总结下,WebWorkerRenderer2类定义了在WebWorker线程中模拟操作DOM节点的方法,并且发出指令向UI线程发送信息。
与WebWorkerRenderer2类对应的是MessageBasedRenderer2类,前者在WebWorker线程中工作,后者在UI线程中工作。同样的,是MessageBasedRenderer2类中也定义了丰富的DOM操作方法(与WebWorkerRenderer2类对应),这些方法才是真正意义上操作DOM的方法,通过调用Renderer2中的相关方法。同时,DOM的事件触发后会通过MessageBus的Sink发送给WebWorker线程中的WebWorkerRendererFactory2类做处理。
WebWorkerRenderer2类既然有个ClientMessageBroker类来作中间代理人,负责传递信息,那么,MessageBasedRenderer2类也需要一个代理人来接头,这就是ServiceMessageBrokerFactory类。它负责注册WebWorkerRenderer2类中DOM操作函数,并接收从ClientMessageBroker传过来的渲染指令,然后触发对应的方法,执行结束后,在反馈给ClientMessageBroker代理人(成功还是失败)。
枯燥无聊的先前知基本都说到了,接下来该干正事了。
统观全局
我们看图说话。
图中只介绍了两个通道的(RENDERER_2_CHANNEL通道和EVENT_2_CHANNEL通道)的通讯流程,还差一个ROUTER_CHANNEL通道没有提及,其通过过程和RENDERER_2_CHANNEL通道类似。
先来介绍一下初始化的部分(图中的蓝色部分),从左到右来介绍。首先左侧MessageBasedRenderer2类初始化的时候创建ServiceMessageBroker类型作为自己的通讯代理人,同时初始化两条通道,创建PostMessageBusSink和Source为通讯做准备(其中事件通道中只用到了Sink),并对Source订阅事件。右侧的WebWorker线程中的初始化操作类似,用到的类不同而已。
在启动时(图中的黄色部分),MessageBasedRenderer2会在start函数中调用registerMethod方法去向ServiceMessageBroker注册DOM操作相关的方法,存储在_methods中,等待触发。
接下来,就是正式运行渲染环节了,避免错乱,更新下图,如下:
图中显示了3种颜色,代表了3个线程间通讯的过程,从绿色的开始说。
在WebWorker线程中,Angular引擎首先会根据页面布局拆分为细化的DOM节点操作,并执行渲染操作。通过callUI调用Broker中的runOnService方法,并存储在_pending容器(存的是什么东西?)中,同时使用Sink向UI线程的Source发送消息,包含id、方法名和参数。UI线程的代理人接收到信息后,触发相应的订阅事件_handleMessage方法,该方法就去_mehtods中找MessageBassedRenderer2在启动时候注册的对应方法并执行,具体过程就是调用Renderer2中相应的DOM操作方法。
等DOM操作结束,就进入了蓝色标示的过程,其实是个反馈的过程。通过Sink向WebWorker线程发送消息,消息内容如下:
{'type': 'result','value': this._serializer.serialize(result, type),'id': id,
}
其中type类型是‘result’(其实还可能是'error',本文未指出),WebWorker线程收到消息后,会触发在初始化时候定义的订阅事件,执行_handleMessage方法,操作_pengding容器,根据id获取对应条目执行(执行的是什么?)并且删除,这样这个蓝色过程就结束了。
那么_pending容器里面存的是什么?执行的又是什么?从字面理解是应该是用于存储'待解决'的事务,这也回答了,怎么处理线程间并发这个问题?在此解答一下,先上相关代码:
interface PromiseCompleter {resolve: (result: any) => void;reject: (err: any) => void;
}
// ...
let completer: PromiseCompleter = undefined !;
let promise = new Promise((resolve, reject) => { completer = {resolve, reject}; });
let id = this._generateMessageId(args.method);
// 存储
this._pending.set(id, completer);
// catch和then
promise.catch((err) => {...});
promise = promise.then((v: any) => this._serializer ? this._serializer.deserialize(v, returnType) : v);
// ... 反馈时
if (message.type === 'result') {this._pending.get(id) !.resolve(message.value);
} else {this._pending.get(id) !.reject(message.value);
}
this._pending.delete(id);
// ...
_pending容器里面存了id和与之对应的Promise对象的 {resolve, reject},并且预先定义好then方法(这里是做了反序列化操作,并没有其余操作),当WebWorker线程接收到type为'result' or 'error'的消息时,并对应执行resolve或者reject方法,以此释放Promise。相信你已经明白了,线程间并发问题就是用过Promise方法来完成同步。
最后来到紫色的过程,UI线程中DOM节点绑定的事件触发后,通过Sink通过事件通道向WebWorker线程的Source发送消息,WebWorker线程收到消息后,触发相应的订阅方法,这里不像渲染通道一样,有反馈过程。可能的原因时,与事件相关的方法(大部分是在对DOM节点操作),还是通过渲染通道(通过绿色和蓝色的过程)通知给UI线程。
这样整个WebWoker Renderer的线程间通讯的部分就介绍完毕了。
回顾下一开始提出的三个问题:
- 通讯信息如何序列化与反序列化?内存数据如何共享? 答:通过RenderStore类。
- 如何打破Webworker线程不能操作DOM节点的局限? 答:通过RENDERER_2_CHANNEL通道。
- 如何处理并发?答:通过操作反馈与Promise机制。
还没完
我猜你一定想知道Angular中是怎么启动WebWorker线程并执行渲染操作?如何开启UI线程中的start方法?来来来,慢慢絮叨。
我们从如何将传统的Angular项目(基于platformBrowserDynamic的JIT项目或者基于platformBrowser的AOT项目)转换成基于platformWorkerAppDynamic的WebWorker项目,可以参考本文一开始提供的DEMO项目或者参考文章《Angular with Web Workers: Step by step》。基于现有的WebWorker项目,我们来讲解一下,启动过程。
首先会调用@angular/platform-webworker中的bootstrapWorkerUi方法启动一个WebWorkerLoader,传入的是一个WebPack打包输出的webworker.bundle.js(可在webpack.config.js输出),基于的文件就是一个platformWorkerAppDynamic的启动文件,其余的配置与传统项无异,由此可见改动成本还是比较小的。
主要还是来看一下bootstrapWorkerUi方法做了些什么?
export function bootstrapWorkerUi(workerScriptUri: string, customProviders: Provider[] = []): Promise<PlatformRef> {// For now, just creates the worker ui platform...const platform = platformWorkerUi([{provide: WORKER_SCRIPT, useValue: workerScriptUri},...customProviders,]);return Promise.resolve(platform);
}
从代码中看出主要是创建一个platformWorkerUi对象,讲loader文件地址传入。
这么关键的一个platformWorkerUi我们简单来将想,该对象通过createPlatformFactory(Angular/core中的方法)创建,并传入一组Provider,包括MessageBasedRenderer2,Serializer,RenderStore,MessageBus等之前介绍过的注入类,
还有一个关键的WebWorkerInstance,申明如下:
@Injectable()
export class WebWorkerInstance {public worker: Worker;public bus: MessageBus;/** @internal */public init(worker: Worker, bus: MessageBus) {this.worker = worker;this.bus = bus;}
}
作为WebWorker的一个实例,包含Woker对象的实例,和MessageBus的实例,那么什么时候调用的init方法初始化呢?接着往下看,
Provider中还有一个关键init时需要的注入类,描述如下:
{provide: PLATFORM_INITIALIZER,useFactory: initWebWorkerRenderPlatform,multi: true,deps: [Injector]
}
里面使用了initWebWorkerRenderPlatform方法,提取梳理出关键的步骤:
const webWorker: Worker = new Worker(url);
const sink = new PostMessageBusSink(webWorker);
const source = new PostMessageBusSource(webWorker);
const bus = new PostMessageBus(sink, source);
WebWorkerInstance.init(webWorker, bus);// initialize message services after the bus has been created
const services = injector.get(WORKER_UI_STARTABLE_MESSAGING_SERVICE);
// 这里的 WORKER_UI_STARTABLE_MESSAGING_SERVICE 在应用中归根到底其实就是调用的MessageBasedRenderer2类
zone.runGuarded(() => { services.forEach((svc: any) => { svc.start(); }); });
根据url路径创建Worder对象,该对应用于PostMessageBusSink和PostMessageBusSource对象初始化,比如在PostMessageBusSource初始化中会对Worker对象addEventListener监听'message'事件。然后使用sink和source实例化PostMessageBus类,再调用WebWorkerInstance对象的init方法。最后,将注入的MessageBasedRenderer2类自动调用start方法。
总结
说一下自己的感受,不要为了用WebWorker线程而用,还是要集合多方面因素来考虑,比如线程间通讯时间,开启线程的性能消耗等,毕竟WebWorker提出的初衷是为了那些计算密集型的操作,被Angular框架使用到渲染中,是一个有突破的创新,但目前并不能支持所有项目的转换,还不稳定(@experimental),请谨慎使用。但相信随着浏览器的发展,为了极致化用户体验,WebWorker的渲染势必会被各大主流前端框架考虑在内。
至此,Angular WebWorker Renderer的前前后后的源码解析就解密完了,肯定有诸多解析不到位的地方,欢迎留言吐槽。
知乎@charway
参考
Angular Platform-Webworker 源码
Angular Web Worker - Building Super Responsive UI
Using Web Workers for more responsive apps
Angular with Web Workers: Step by step
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- angular基础( 1.2 -- 2.0版本 )
教程推荐位置:http://www.angularjs.net.cn/tutorial/ 本人是比较倾向《angular权威教程》和angular手册结合的方式学习。 调试工具极力推荐:ng-inspector 1、数据绑定 angular数据绑定的两个方式:(1)ng-bind指令&…...
2024/5/1 21:43:55 - 知乎|推荐10个大学生需要收藏的良心网站
1:万千合集站 http://www.hejizhan.com/html/search/ 万千合集站是一个高质量论文,文档搜索网站,是一个非常适合大学生的一个网站。 它支持各种不同学科论文,文档搜索,包括:数学建模,电气工程…...
2024/5/1 22:33:48 - 前端框架:Angular React 和 Vue的比较
前端这几年的技术发展很快,细分下来,主要可以分成四个方面: 1.开发语言技术,主要是ES6&7,coffeescript,typescript等; 2.开发框架,如Angular,React,Vue.jsÿ…...
2024/5/2 1:43:15 - 使用Angular6+Bootstrap写的博客生成器
起源 我是工作两年才开始写博客的。 之前也产生过写博客的想法,但是为什么没有做呢?主要是觉得自己技术积累的还比较少,没什么可写的。有时候产生了一些想法或者做的一些事情,就直接记在笔记上了,记完之后觉得反正也…...
2024/4/21 2:24:53 - Angular页面传参办法
作者:Ye Huang链接:https://www.zhihu.com/question/33565135/answer/69651500来源:知乎著作权归作者所有,转载请联系作者获得授权。1. 基于ui-router的页面跳转传参(1) 在AngularJS的app.js中用ui-router定义路由,比如…...
2024/5/2 4:12:36 - 关于angular与vue的选择
mv*框架知乎上关于vue与angular的优劣辩论非常火热,总的来说,大型项目推荐使用angular,中小型项目推荐使用vue。细的分析会涉及方方面面,一时难以分出优劣,客观来说,vue门槛低、入手容易,但是高…...
2024/5/2 1:19:04 - 前端学习总结(二十三)——前端框架天下三分:Angular React 和 Vue的比较
前端这几年的技术发展很快,细分下来,主要可以分成四个方面: 1.开发语言技术,主要是ES6&7,coffeescript,typescript等; 2.开发框架,如Angular,React,Vue.js…...
2024/4/21 2:24:50 - 【荐】Angular官方代码风格指南
本文为笔者对Angular官网风格指南的整理版本,删除/增加了部分内容。另外,原文对每个规范都作出了原因的解释,个别还有示例,需要的请点击查看原文。 原链接:英文文档 / 中文文档 单一职责 单一…...
2024/4/20 20:25:12 - angular 4 实现的tab栏切换
管理系统 tab 切换页,是一种常见的需求,大概如下:点击左边菜单,右边显示相应的选项卡,然后不同的选项卡面可以同时编辑,切换时信息不掉失! 用php或.net,java的开发技术,大概是切换显示,然后加一…...
2024/4/20 20:25:11 - angular 零碎
相关链接 api(需要FQ)ui-router 知乎作用域 angular 中作用域的概念是一个亮点,由不同的指令、controller等作用域组成的作用域树就是一个app。简单理解一个controller的作用域就是一个$scope,在此controller下的所有指令的操作都是在此作用域下&#x…...
2024/4/20 20:25:10 - Angular2与React,前端的未来志向何方?
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。作者:徐飞链接:https://www.zhihu.com/question/38576309/answer/78211671来源:知乎去年年底,我回答过一个问题:2014 年末有哪些比较…...
2024/4/20 20:25:09 - 前端框架Angular React 和 Vue的比较
前端这几年的技术发展很快,细分下来,主要可以分成四个方面: 1.开发语言技术,主要是ES6&7,coffeescript,typescript等; 2.开发框架,如Angular,React,Vue.jsÿ…...
2024/4/21 2:24:49 - Angular Dialog 组件的设计与实现
你好,我是徐晓东,笔名燕云长风。大漠穷秋于 2019-03-16 21:22 赠此笔名。 寓意:结合李白著名的边塞诗《关山月》取【燕云长风】—— 长风几万里,吹度玉门关。 yycf-dialog 是一个基于Angular开发的通用业务组件库,包含…...
2024/4/21 2:24:48 - angular学习资源
2019独角兽企业重金招聘Python工程师标准>>> 作者:VTHINKXIE 链接:https://zhuanlan.zhihu.com/p/36385830 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 博客及文章 中文 Angul…...
2024/4/21 2:24:47 - Angular系列之AoT编译
概览 众所周知, angular应用在可执行之前, angular应用中的组件和模板必须被转化为可以被浏览器识别的javascript代码, 而这种转化正是通过angualr自身的编译器所执行的. angular提供了两种编译方式, 即AOT(预编译)和JIT(即使编译), 其中JIT为默认的编译方式 AOT即 Ahead of ti…...
2024/4/28 9:28:24 - 【Angular】关于angular引用第三方组件库无法改变其组件样式
【Angular】关于angular引用第三方组件库无法改变其组件样式 :host ::ng-deep css修改:无效 .ant-input-affix-wrapper .ant-input:not(:first-child){padding-left: 30px; } 修改上面就正常了 :host ::ng-deep .ant-input-affix-wrapper .ant-input:not(:firs…...
2024/4/29 6:16:39 - 16个最佳Angular UI框架
angular ui框架Angular is a full-fledged framework with its own tooling and best practice implementation designed on top.Angular是一个成熟的框架,其顶部设计了自己的工具和最佳实践实现。 It encourages the use of library components by splitting them…...
2024/4/27 6:44:41 - Angular引入第三方库--问题解决方法
转自:http://blog.csdn.net/yuzhiqiang_1993/article/details/71215232 如果我们想在Angular中使用第三方的库,比如jQuery或bootstrap等,该如果做呢? 首先我们先来看看package.json这个文件,在目录介绍那篇博客中我们已经知道&…...
2024/4/25 21:01:15 - Angular dart 之 使用Angular component库
Dart是一门可以同时开发app,web,server的语言。 在web使用中,主要使用AngularDart开发。 在引入Angular component时,样式没有生效。 经过Google之后,找到答案: https://patorash.hatenablog.com/entry…...
2024/4/21 2:24:43 - Angular集成jQuery库
当构建 Angular 应用时,我们可以使用jQuery等第三方库。 集成方式有以下两种: 1、安装库 在项目根目录下执行以下命令,使用 npm 包管理器来安装该库及其依赖: npm install jquery --save npm install types/jquery 在使用该库…...
2024/4/25 17:17:57
最新文章
- PHP定时任务框架taskPHP3.0学习记录7宝塔面板手动可以执行自动无法执行问题排查及解决方案(sh脚本、删除超过特定天数的日志文件、kill -9)
PHP定时任务框架taskPHP3.0学习记录 PHP定时任务框架taskPHP3.0学习记录1(TaskPHP、执行任务类的实操代码实例)PHP定时任务框架taskPHP3.0学习记录2(环境要求、配置Redis、crontab执行时间语法、命令操作以及Screen全屏窗口管理器࿰…...
2024/5/2 5:02:27 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 算法四十天-删除排序链表中的重复元素
删除排序链表中的重复元素 题目要求 解题思路 一次遍历 由于给定的链表是排好序的,因此重复的元素在链表中的出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。 具体地,我们从指针cur指向链表的头节…...
2024/5/1 13:07:13 - STM32实现软件SPI对W25Q64内存芯片实现读写操作
先看看本次实验的成果吧: 这么简单的一个程序,我学习了一个星期左右,终于把所有的关节都打通了。所有代码都能什么都不看背着敲出来了。为了使自己的记忆更为清晰,特意总结了一个思维导图,感觉自己即便是日后忘记了看一…...
2024/5/1 12:08:49 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/30 18:14:14 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/30 18:21:48 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/30 9:43:22 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下: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