惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
O
OpenAI News
AI
AI
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Heimdal Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
S
SegmentFault 最新的问题
宝玉的分享
宝玉的分享
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
TaoSecurity Blog
TaoSecurity Blog
The Cloudflare Blog
V
Visual Studio Blog
Forbes - Security
Forbes - Security
Apple Machine Learning Research
Apple Machine Learning Research
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
The Last Watchdog
The Last Watchdog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
Security Latest
Security Latest
量子位
W
WeLiveSecurity
V
V2EX
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
小众软件
小众软件
The Hacker News
The Hacker News
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
博客园 - 聂微东
T
Troy Hunt's Blog
S
Schneier on Security
有赞技术团队
有赞技术团队
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
P
Privacy International News Feed
Jina AI
Jina AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

Minko Gechev's blog

skillgrade Unit Tests for AI Agent Skills You Should Care About AI Generative Development LLM-first Web Framework Reactive framework in ~200 lines of JavaScript Managing Angular Are LLMs going to replace us? Prefetching Heuristics Design Patterns in Open Source Projects - Part II Design Patterns in Open Source Projects - Part I What I learned doing 125 public talks - Part I Dynamic imports solve all the problems, right? 5 Angular CLI Features You Didn't Know About Angular quicklink Preloading Strategy Introducing Bazel Schematics for Angular CLI Building TypeScript Projects with Bazel Joining Google Playing Mortal Kombat with TensorFlow.js. Transfer learning and data augmentation Fast, extensible, configurable, and beautiful linter for Go Introducing Guess.js - a toolkit for enabling data-driven user-experiences on the Web Machine Learning-Driven Bundling. The Future of JavaScript Tooling. JavaScript Decorators for Declarative and Readable Code 3 Tricks For Using Redux and Immutable.js with TypeScript Follow Your Dream Career with Open Source. Personal Story. Redux Anti-Patterns - Part 1. State Management. Faster Angular Applications - Understanding Differs. Developing a Custom IterableDiffer Faster Angular Applications - Part 2. Pure Pipes, Pure Functions and Memoization Faster Angular Applications - Part 1. On Push Change Detection and Immutability Understanding Dynamic Scoping and TemplateRef Implementing a Simple Compiler on 25 Lines of JavaScript Developing Statically Typed Programming Language WebVR for a Gamified IDE 7 Angular Tools That You Should Consider Announcing ngrev - Reverse Engineering Tool for Angular Implementing Angular's Dependency Injection in React. Understanding Element Injectors. Distributing an Angular Library - The Brief Guide Angular in Production Ahead-of-Time Compilation in Angular 2.5X Smaller Angular 2 Applications with Google Closure Compiler Using Stripe with Angular (Deprecated) Building an Angular Application for Production Implementing the Missing "resolve" Feature of the Angular 2 Router Scalable Single-Page Application Architecture Managing ambient type definitions and dealing with the "Duplicate identifier" TypeScript error Static Code Analysis of Angular 2 and TypeScript Projects Enforcing Best Practices with Static Code Analysis of Angular 2 Projects ViewChildren and ContentChildren in Angular Dynamically Configuring the Angular's Router Angular 2 Hot Loader Aspect-Oriented Programming in JavaScript Flux in Depth. Store and Network Communication. Using JSX with TypeScript Flux in Depth. Overview and Components. Even Faster AngularJS Data Structures Boost the Performance of an AngularJS Application Using Immutable Data - Part 2 Angular2 - First Impressions Build Your own Simplified AngularJS in 200 Lines of JavaScript Persistent State of ReactJS Component Boost the Performance of an AngularJS Application Using Immutable Data Processing Binary Protocols with Client-Side JavaScript Stream your Desktop to HTML5 Video Element Multi-User Video Conference with WebRTC Asynchronous calls with ES6 generators Binary Tree iterator with ES6 generators WebRTC chat with React.js AngularJS in Patterns (Part 3) AngularJS in Patterns (Part 2). Services. Using GitHub Pages with Jekyll! AngularJS in Patterns (Part 1). Overview of AngularJS Singleton in JavaScript Express over HTTPS What I get from the JavaScript MV* frameworks Remote Desktop Client with AngularJS and Yeoman The magic of $resource (or simply a client-side Active Record) AngularJS Inheritance Patterns AngularAOP v0.1.0 Advanced JavaScript at Sofia University AngularJS style guide Lazy prefetching of AngularJS partials VNC client on 200 lines of JavaScript Aspect-Oriented Programming with AngularJS CSS3 flipping effect Practical programming with JavaScript Why I should use publish/subscribe in JavaScript JavaScript, the weird parts Functional programming with JavaScript plainvm Looking for performance? Probably you should NOT use [].sort (V8) JavaScript image scaling ELang Caching CSS with localStorage Self-invoking functions in JavaScript (or Immediately Invoked Function Expressions) Asus N56VZ + Ubuntu 12.04 (en) Asus N56VZ + Ubuntu 12.04 Debian Squeeze + LXDE on Google Nexus S (or having some fun while suffering) HTML5 image editor Курсови проекти – ФМИ Carousel Gallery SofiaJS...
Lazy Loading of Route Components in Angular 2
2015-09-30 · via Minko Gechev's blog

Edit · Sep 30, 2015 · 7 minutes read · Follow @mgechev JavaScript Angular 2 Angular Router Performance

Warning: This version of the Angular 2 router is now deprecated! This means that soon the used below APIs will no longer be available.

For the examples in the content below I’ve used the angular2-seed project. The code for the article could be found at my GitHub account.

This blog post is mostly about performance and more accurately - lazy loading. Before we get started lets make a quick recap of what problem we’re about to solve.

Background

Disclaimer: Angular 2 is still in alpha. All the APIs we’re using here are quite likely to change. If you notice that the article is not up to date, please open a PR, leave a comment or contact me via twitter.

In order to get familiar with the upcoming content you need to have basic understanding of Angular 2 and the component based router introduced by the framework. Good introduction to routing in Angular 2 could be found here.

Sample Application

Lets take a look at this sample application:

import {Component, View, bootstrap} from 'angular2/angular2';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router';
import {Home} from './components/home/home';
import {About} from './components/about/about';

@Component({
  selector: 'app'
})
@RouteConfig([
  { path: '/', component: Home, name: 'home' },
  { path: '/about', component: About, name: 'about' }
])
@View({
  templateUrl: './app.html',
  styleUrls: ['./app.css'],
  directives: [ROUTER_DIRECTIVES]
})
class App {}

bootstrap(App, [ROUTER_PROVIDERS]);

This is the root component of angular2-seed.

In the snippet above we create a new component with controller the App class. We also register two routes:

  • / - once opened the Home component will be rendered.
  • /about - once opened the About component will be rendered.

Here’s the implementation of the About component:

import {Component, View, CORE_DIRECTIVES} from 'angular2/angular2';

import {NameList} from '../../services/NameList';

@Component({
  selector: 'about',
  providers: [NameList],
  templateUrl: './components/about/about.html',
  directives: [CORE_DIRECTIVES]
})
export class About {
  constructor(public list: NameList) {}
  addName(newname):boolean {
    this.list.add(newname.value);
    newname.value = '';
    return false;
  }
}

The About component uses the service NameList, which is located under ../../services/NameList. So far so good, now lets take a look at how our application looks like:

Sample app

As we can see from Chrome DevTools’ Network tab, during the initial page load all the components and services used in the entire application are being downloaded. However, in order to render the Home view we don’t need the About component, neither the NameList service (usually the template of the About component will be requested as well. However, in this example it is being inlined inside the component by a gulp task).

Place for Improvements!

In the sample application above, loading a couple of files more is not such a big problem since the entire app consists only two views and a single service. However, in a real-life application downloading the entire dependency graph during the initial page load may create quite poor user experience. Imagine we had n views, each of these n components had m dependencies, which had another k dependencies, etc.

Lazy Loading

The practice of lazy loading is quite common in web development. We lazy load assets, partials, basically whatever we need in order to speedup our load time and we load it on demand!

The Problem

Although the About component is not essential for rendering the Home component it is referenced directly inside the file, which contains the definition of the root component of our application (App). App cannot be rendered until all of the dependencies, which are declared inside of the file are not loaded. Although the ES2015 modules have implicit asynchronous behavior the rendering of the App component happens synchronously, since we need to resolve all of its dependencies before it appears onto the screen.

In order to workaround this issue we can use the ES2015 module loader imperative API.

AsyncRoute

The obvious Angular solution to the problem us using AsyncRoute. This is class, which implements RouteDefinition and allows asynchronous loading of the component associated with given route. This allows on demand loading of the component’s dependencies as well. Here’s now our definition will look like with AsyncRoute:

@RouteConfig([
  { path: '/', component: Home, name: 'home' },
  new AsyncRoute({
    path: '/about',
    loader: () => System.import('./components/about/about').then(m => m.About),
    name: 'about'
  })
])

Basically we register two routes:

  • A regular route
  • Async route. The async route accepts as argument a loader. The loader is a function that must return a promise, which needs to be resolved with the component that needs to be rendered.

So far so good! Everything looks great and we achieved our goal. However, there are some more advanced cases we may want to cover. For example, we may need to throw events when the route change has started and completed. In the case of AsyncRoute we can implement a generic loader, which takes care of this. However, we may want to implement something like a splash screen or have even further control on the component’s rendering. In such case we may use a:

Virtual Proxy

The Angular router accepts a component for value of the component property of all of its routes definitions. However, instead of providing the concrete component, which needs to be rendered we can provide a component proxy. This is the Virtual Proxy pattern. Inside the component proxy we can load the target component and later, when it is loaded, using the DynamicComponentLoader we can render it onto the screen.

Lets define a componentProxyFactory, which will be responsible for creating component proxies:

export class ComponentProvider {
  path:string;
  provide:{(module:any):any};
}

const PROXY_CLASSNAME = 'component-wrapper';
const PROXY_SELECTOR = `.${PROXY_CLASSNAME}`;

export function componentProxyFactory(provider: ComponentProvider): Type {
  @Component({
    selector: 'component-proxy',
    providers: [provide(ComponentProvider, { useValue: provider })]
  })
  @View({
    template: `<span #content/>`
  })
  class VirtualComponent {
    constructor(
      el: ElementRef,
      loader:DynamicComponentLoader,
      inj:Injector,
      provider:ComponentProvider) {
        System.import(provider.path)
        .then(m => {
          loader.loadIntoLocation(provider.provide(m), el, 'content');
        });
      }
  }
  return VirtualComponent;
}

Now lets take a look at the code step by step:

  1. We define a class called ComponentProvider. It contains two properties:
  • path - a path to the component, which will be used by the module loader.
  • provide - a provider, which will return the target component based on the passed module as argument
  1. We define a function called componentProxyFactory:
  • This function accepts as argument a ComponentProvider object and returns a new component called VirtualComponent.
  • The VirtualComponent defines a single provider, in order to allow the provider to be passed as argument to the constructor through DI.
  • Inside VirtualComponent’s constructor we load the module based on the provider’s path and right after that loaded in the template using: loader.loadIntoLocation(provider.provide(m), el, 'content');

And thats all!

Now lets take a look how we can refactor our root component in order to take advantage of the lazy loading:

import {Component, View, bootstrap} from 'angular2/angular2';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router';
import {Home} from './components/home/home';

import {componentProxyFactory} from './component_proxy';

@Component({
  selector: 'app',
})
@RouteConfig([
  { path: '/', component: Home, name: 'home' },
  {
    path: '/about',
    component: componentProxyFactory({
      path: './components/about/about',
      provide: m => m.About
    }),
    name: 'about'
  }
])
@View({
  templateUrl: './app.html',
  styleUrls: ['./app.css'],
  directives: [ROUTER_DIRECTIVES]
})
class App {}

bootstrap(App, [ROUTER_PROVIDERS]);

Now the file doesn’t contain any reference to the About component. Instead it registers in the route definition for the About component using:

{
  path: '/about',
  component: componentProxyFactory({
    path: './components/about/about',
    provide: m => m.About
  }),
  name: 'about'
}

Results

Lets take a look at how the page load will look this time:

Sample lazy app

As we can see there are two additional resources, which are being downloaded on demand:

  • about.js
  • NameList.js

Victory

Conclusion

There are still a lot of things to be considered. For example, in a real-life application you’ll most likely have different bundles in order to reduce the number of downloaded files even further. In our case we can combine the About component and NameList in a single file during the build process.

Also do not forget that Angular 2 is still in early alpha so the framework and the entire API are under development. However, no one stops you from having fun with it!