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

推荐订阅源

N
News and Events Feed by Topic
GbyAI
GbyAI
博客园 - Franky
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
人人都是产品经理
人人都是产品经理
Microsoft Azure Blog
Microsoft Azure Blog
The Register - Security
The Register - Security
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
博客园 - 【当耐特】
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Project Zero
Project Zero
量子位
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
美团技术团队
Attack and Defense Labs
Attack and Defense Labs
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Blog of Author Tim Ferriss
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
罗磊的独立博客
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
L
LINUX DO - 最新话题
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
博客园 - 聂微东
A
About on SuperTechFans
PCI Perspectives
PCI Perspectives
D
Docker

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 Lazy Loading of Route Components in Angular 2 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 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 prefetching of AngularJS partials
2013-10-01 · via Minko Gechev's blog

Edit · Oct 1, 2013 · 6 minutes read · Follow @mgechev AngularJS JavaScript Lazy loading performance Pre-fetching

This blog post is concentrated about web performance. I’ll skip the well known stuff about combining images into sprites, inlining images, DNS pre-fetching, combining and minifying script files, gzipping and so on. There are plenty of articles and tools which will help you about these things. There are also excellent researches on these topics, few of the best I’ve read are these by Mobify, Web Performance Daybook Volume, High Performance Web Sites and Critical rendering path – Crash course on web performance and many others. I hope HTTP 2.0 will eliminate few of the dirty hacks we all make…
I’ll focus on the performance in the Single-Page Applications and especially template prefetching strategy we use in the web application of Brownie Points. I’ll give code samples with AngularJS but these methods can be also applied with Ember.js, Backbone.js (with little more pain) and other MV* frameworks, I guess.
To find the best approach for your app you should understand it very well and know all the relations between the different pages. One way to do this is by visualising all the relations using UML state machine diagram. It will show you how your pages are connected, triggering of which event will lead to page change (events), based on which conditions the pages will change (guards) and what is done during the transition (actions).
For illustrating the way this partials pre-fetching strategy works, I’ll use example with a web application which is web interface for revision control system.
So, we have the following pages:

  • Home
  • User profile
  • User projects
  • Project
  • Project issues
  • Project wiki

From the home screen the user will be able to view the profile of chosen user or navigate to his own projects. From the user’s profile view the user will be able to navigate to projects list or go back to the home screen. In case the user view the projects list (his own or projects of another user) he can navigate to a project details or go back to the home screen. From the project view the user can go to the wiki or issues pages (if the page exists).

This brief description is illustrated by the following state diagram (some events, actions and guards are not very descriptive because the diagram would become messy with verbose explanations).

revision-control-state-machine

UML state machine diagram of SPA

It is not exactly state machine diagram because the beginning and end pseudo states are missing, but it illustrates our idea pretty well.

If the user is in the home page he may go to the projects page or the user’s profile page, lets suppose that the same template is used for his own projects and for other users’ projects. Something we can do is to prefetch the templates for the projects list and user’s profile, these are only 2 pages which are neighbours of the home page so the browser will create two threads (eventually), using XHR we will fetch the templates and put them in the $templateCache using the template url as key and it’s content as content.

We can define our routes relations like:

var pageRelations = {
  'home': ['user-profile', 'user-projects'],
  'user-project': ['home', 'project'],
  'user-profile': ['home', 'user-projects', 'project'],
  'project': ['user-projects', 'project-issues', 'project-wiki'],
  'project-wiki': ['project'],
  'project-issues': ['project']
};

With routing definition like this:

var routes = [
  {
    id: 'home',
    url: '/home',
    templateUrl: 'partials/home.html',
    controller: 'HomeCtrl'
  },
  {
    id: 'user-projects',
    url: '/projects-list/:userid',
    templateUrl: 'partials/user-projects.html',
    controller: 'ProjectsListCtrl',
    resolve: {
      'ProjectsList': function ($routeParams, ProjectsService) {
         return ProjectsService.getList($routeParams.userid);
      }
    }
  },
  {
    id: 'user-profile',
    url: '/user-profile/:userid',
    templateUrl: 'partials/user-profile.html',
    controller: 'UserProfileCtrl',
    resolve: {
      'UserProfile': function ($routeParams, UserService) {
        return UserService.getProfile($routeParams.userid);
      }
    }
  },
  {
    id: 'project',
    url: '/project/:projectid',
    templateUrl: 'partials/project.html',
    controller: 'ProjectCtrl',
    resolve: {
      'Project': function ($routeParams, ProjectsService) {
        return ProjectsService.getDetails($routeParams.projectid);
      }
    }
  },
  {
    id: 'project-wiki',
    url: '/project-wiki/:projectid',
    templateUrl: 'partials/project-wiki.html',
    controller: 'WikiCtrl',
    resolve: {
      'Project': function ($routeParams, ProjectsService) {
        return ProjectsService.getWiki($routeParams.projectid);
      }
    }
  },
  {
    id: 'project-issues',
    url: '/project-issues/:projectid',
    templateUrl: 'partials/project-issues.html',
    controller: 'ProjectCtrl',
    resolve: {
      'Project': function ($routeParams, ProjectsService) {
        return ProjectsService.getIssues($routeParams.projectid);
      }
    }
  }
];

routes.forEach(function (r) {
  $routeProvider.when(r.url, r);
});

And to prefetch the neighbour views’ templates when we are at specific state:

var prefetched = {};
$rootScope.$on('$routeStateChange', function (evnt, state) {
  pageRelations[state.id].forEach(function (c) {
    var n = routes[c];
    if ($templateCache.get(n.templateUrl)) return; //prevent the prefetching if the template is already in the cache
    $http.get(n.templateUrl).success(function (t) {
      $templateCache.put(n.templateUrl, t);
    });
  });
});

The pre-fetching control can be put at directive or top-level controller. I prefer the directive option, because if there are more things to be prefetched, not only the templates, you can configure it using markup and you won’t have to change your JavaScript code when you decide to change your pre-fetching options.

If we look more abstract of the thing we did – we actually created a graph presented with list of neighbours and in each page change we pre-fetch the templates of all its neighbours.

With not so complex web application everything is cool, the browser can run up to 6 different threads, one for each XHR. But when from a single page the user can go to 30 others and your server response time is not that fast the things may become not very efficient. If the order of the neighbours in the array is not the most appropriate one the user may have to wait because the first few threads won’t fetch the template required by him.
To do it better you should review each connection between the pages and sort the neighbours arrays by some kind of weight. It can be statistical data gained from the user, your suggestion, six sense, you can even roll dice if you think you’ll be more accurate. To keep the array ordered by hand is error-prone so you can do something like:

var pageRelations = {
  'home': [{ name: 'user-profile', weight: 10 }, { name: 'user-projects', weight: 8 }],
  'user-projects': [{ name: 'home', weight: 7 }, { name: 'project', weight: 9 }],
  'user-profile': [{ name: 'home', weight: 8 }, { name: 'user-projects', weight: 4 }, { name: 'project', weight: 9 }],
  'project': [{ name: 'user-projects', weight: 8 }, { name: 'project-issues', weight: 9 }, { name: 'project-wiki', weight: 6 }],
  'project-wiki': [{ name: 'project', weight: 9 }],
  'project-issues': [{ name: 'project', weight: 9 }]
};

Now the pageRelations is a hash table with keys – the web app’s pages, values – all neighbour views for the current one, and rating associated to each neighbour.
In that way you actually use a directed graph with weighted edges, all you have to do is to walk the neighbours of the current node (current page) by their priority and prefetch the template for each node:

$rootScope.$on('$routeStateChange', function (evnt, state) {
  pageRelations[state.id].sort(function (a, b) {
    return b.weight - a.weight;
  }).forEach(function (c) {
    var n = routes[c.name];
    if ($templateCache.get(n.templateUrl)) return; //prevent the prefetching if the template is already in the cache
    $http.get(n.templateUrl).success(function (t) {
      $templateCache.put(n.templateUrl, t);
    });
  });
});

And that’s all. Possible issue which should be taken under attention is the loading of the images used by the prefetched templates, it’s not enough to load only the html, usually the images takes more bandwidth. Here you can use different approaches – parse the template, take all “img” elements and pre-fetch their source. Anyway, this doesn’t work with the CSS “background-image” property. When there are elements with “background-image” property you can get it’s value only after the element is added to the DOM tree but adding each template and walking its elements may have performance impact when you have large, complex templates.