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

推荐订阅源

Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
C
Cisco Blogs
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
L
LINUX DO - 热门话题
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Security Archives - TechRepublic
Security Archives - TechRepublic
TaoSecurity Blog
TaoSecurity Blog
V2EX - 技术
V2EX - 技术
H
Heimdal Security Blog
S
Security Affairs
L
Lohrmann on Cybersecurity
Hacker News - Newest:
Hacker News - Newest: "LLM"
Simon Willison's Weblog
Simon Willison's Weblog
WordPress大学
WordPress大学
小众软件
小众软件
Security Latest
Security Latest
AWS News Blog
AWS News Blog
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
F
Full Disclosure
S
Schneier on Security
L
LangChain Blog
MyScale Blog
MyScale Blog
Know Your Adversary
Know Your Adversary
P
Privacy International News Feed
Google Online Security Blog
Google Online Security Blog
Scott Helme
Scott Helme
Stack Overflow Blog
Stack Overflow Blog
爱范儿
爱范儿
A
Arctic Wolf
Martin Fowler
Martin Fowler
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
The Register - Security
The Register - Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
Latest news
Latest news
F
Fortinet All Blogs
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
Hacker News: Ask HN
Hacker News: Ask HN

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 Lazy prefetching of AngularJS partials VNC client on 200 lines of JavaScript 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...
Aspect-Oriented Programming with AngularJS
2013-08-07 · via Minko Gechev's blog

Edit · Aug 7, 2013 · 7 minutes read · Follow @mgechev AngularJS aop aspect-oriented programming Computer science Development Internet JavaScript Programming programming languages Projects

In the following blog post I’ll write few words about what is Aspect-Oriented Programming, why I think it will be useful in AngularJS and I’m also going to give you a short tutorial for using a simple AOP framework I’ve developed.

First things first. What is AOP? As we all know OOP is awesome! It gives us many tools for making our development process simpler. Its core principles are Abstraction, Encapsulation, Inheritance and Polymorphism.

Abstraction helps us build complex applications without thinking for all details. We just “find” the correct level of abstraction for the current phase of development and use it until it’s useful for us. For example when we develop complex OS the first (or one of the first) levels of abstraction, I guess, will include creating a facade for all different hardware platforms but after that the hardware differences wont matter for us and we’ll use higher level interface.

Encapsulation and abstraction are complementary concepts. Encapsulation gives us more details about the implementation behind the visible interface which is our abstraction of the given class or object.

Inheritance gives us code reuse, and polymorphism gives us a common way of handling different instances of different classes in the same hierarchy (and few more things but let’s stop here).

But what we don’t have?

Let’s define the concept of cross-cutting concern:

In computer science, cross-cutting concerns are aspects of a program that affect other concerns. These concerns often cannot be cleanly decomposed from the rest of the system in both the design and implementation, and can result in either scattering (code duplication), tangling (significant dependencies between systems), or both.

The most common examples for cross-cutting concerns are logging, authentication and transactions.
Let’s focus in logging. We may need to log different informations when different methods are called. That means we should have things like:

function foo() {
  Logger.log('log before');
  //body
  Logger.log('log after');
}

If we change the interface of our logger we should change it everywhere, this may affect hundreds of different files.
The situation can become even more complex if we add authentication:

function foo() {
  try {
    Authotization.isAuthorized();
    //body
  } catch (e) {
    //handle the error
  }
}

It may look ok for one or few functions/methods but if their count increase you can shoot yourself in the foot with so many duplicates.
OOP don’t gives us tools for handling such problems. It may suggest to create few helper classes and just copy and paste pieces of code from one place to another.

In AOP we have few more concepts: joint-point – this is place where something happen. For example call of procedure, return of result by a function, throw of exception, call of constructor, etc.

We have also pointcuts. Pointscuts help us describe one or more joint-points. The last concept I’ll define are the advices. They are pieces of code which will be executed in given moment (when joint-points is encountered during the program runs).

To show you how AOP can be useful in AngularJS let me introduce you AngularAOP.

AngularAOP

You can define the cross-cutting concerns in separate services. For example here is a definition of logging service which logs the method calls and thrown exceptions:

DemoApp.factory('Logger', function () {
    return function (args) {
        if (args.exception) {
            console.log('%cException: ' + args.exception.message + '. '
                + args.method + ' called before proper authorization.',
                'color: red; text-weight: bold; font-size: 1.2em;');
        }
        var throwData = (args.exception) ? ' and threw: ' + args.exception.message : '';
        console.log('Method: ' + args.method + ', Pointcut: ' + args.when + ', with arguments: ' +
                    angular.toJson(args.args) + throwData);
    };
});

The definition of that service doesn’t differ from the usual service definition.
Here is definition of one more service which can cause problems with the code maintenance because it is a cross-cutting concern:

DemoApp.factory('Authorization', function (User) {
    return function () {
        if (User.getUsername() !== 'foo' &&
            User.getPassword() !== 'bar') {
            throw new Error('Not authorized');
        }
    };
});

The given service just checks whether user’s user name and password are equal respectively to “foo” and “bar”, if they are not equal to these values the service throws an Error(‘Not authorized’).

We may want to apply authorization for reading news:

DemoApp.service('ArticlesCollection', function ($q, $timeout, execute, Logger, Authorization) {

    var sampleArticles = [
            { id: 0, title: 'Title 1', content: 'Content 1' },
            { id: 1, title: 'Title 2', content: 'Content 2' },
            { id: 2, title: 'Title 3', content: 'Content 3' }
        ],
        privateArticles = [
            { id: 3, title: 'Title 4', content: 'Content 4' },
            { id: 4, title: 'Title 5', content: 'Content 5' }
        ],
        api = {
            loadArticles: function () {
                var deferred = $q.defer();
                $timeout(function () {
                    deferred.resolve(sampleArticles);
                }, 1000);
                return deferred.promise;
            },
            getArticleById: function (id) {
                for (var i = 0; i < sampleArticles.length; i += 1) {
                    if (sampleArticles[i].id === id)  {
                        return sampleArticles[i];
                    }
                }
                return undefined;
            },
            getPrivateArticles: function () {
                return privateArticles;
            }
        };
    return api;
});

This is simple service which contains two kinds of articles (simple object literals): sampleArticles and privateArticles. The api object is the actual service public interface.

We may want to apply authorization to the private articles, before the getPrivateArticles method return its result. The usual way to do it is:

getPrivateArticles: function () {
    Authorization();
    return privateArticles;
}

We may also want to apply authorization to the getArticleById method, so:

getArticleById: function (id) {
    Authorization();
    for (var i = 0; i < sampleArticles.length; i += 1) {
        if (sampleArticles[i].id === id)  {
            return sampleArticles[i];
        }
    }
    return undefined;
}

We have two duplicate lines of code. At this moment it’s not a big deal but we may want to add logging and see special error message in the console when Error is thrown:

//...
getPrivateArticles: function () {
    try {
        Authorization();
        return privateArticles;
    } catch (e) {
        console.log('%cException: ' + e.message + '. getPrivateArticles called before proper authorization.',
            'color: red; text-weight: bold; font-size: 1.2em;');
    }
},
getArticleById: function (id) {
    try {
        Authorization();
        for (var i = 0; i < sampleArticles.length; i += 1) {
            if (sampleArticles[i].id === id)  {
                return sampleArticles[i];
            }
        }
    } catch (e) {
        console.log('%cException: ' + e.message + '. getArticleById called before proper authorization.',
            'color: red; text-weight: bold; font-size: 1.2em;');
    }
    return undefined;
}
//...

Now we have a lot of duplicates and if we want to change something in the code which authorises the user and logs the error we should change it in both places. We may have service with large interface which requires logging and authorisation (or something else) in all of its methods or big part of them. In this case we need something more powerful and the Aspect-Oriented Programming gives us the tools for that.

We can achieve the same effect as in the code above just by applying Authorization and Logger service to the api object:

return execute(Logger).onThrowOf(execute(Authorization).before(api, {
    methodPattern: /Special|getArticleById/
}));

This code will invoke the Authorization service before executing the methods which match the pattern: /Special|getArticleById/ when an Error is thrown the Logger will log it with detailed information. Notice that onThrowOf, before and all the methods listed below return object with the same methods so chaining is possible. We can also match the methods not only by their names but also by their arguments:

return execute(Logger).onThrowOf(execute(Authorization).before(api, {
    methodPattern: /Special|getArticleById/,
    argsPatterns: [/^user$, /^[Ii]d(_num)?$/]
}));

Now the aspects will be applied only to the methods which match both the methodPattern and argsPatterns rules.

Currently execute supports the following pointcuts:

  • before – executes given service before the matched methods are invoked.
  • after – executes given service after the matched methods are invoked.
  • around – executes given service before and after the matched methods are invoked.
  • onThrowOf – executes when an Error is thrown by method from the given set of matched methods.
  • onResolveOf – executes after promise returned by a method from the given set of matched methods is resolved but before the resolve callback is invoked.
  • afterResolveOf – executes after promise returned by a method from the given set of matched methods is resolved but after the resolve callback is invoked.
  • onRejectOf – executes after promise returned by a method from the given set of matched methods is rejected.

Aspects can be applied not only to objects but also to functions:

DemoApp.factory('ArticlesCollection', function ($q, $timeout, execute, Logger, Authorization) {
    return execute(Logger).before(function () {
        //body
    });
});

AngularAOP can be found at: GitHub