npm install -g bower
21 | - grunt-cli npm install -g grunt-cli
22 | - karma npm install -g karma
23 |
24 | ## Installation
25 |
26 | To get the source of this project clone the git repository via:
27 |
28 | ````
29 | $ git clone https://github.com/PascalPrecht/angular-component-seed
30 | ````
31 |
32 | This will clone the complete source to your local machine. Navigate to the project folder
33 | and install all needed dendencies via **npm** and **bower**:
34 |
35 | ````
36 | $ npm install
37 | $ bower install
38 | ````
39 |
40 | The project is now installed and ready to be built.
41 |
42 | ## Building
43 |
44 | This repo comes with a few **grunt tasks** which help you to automate
45 | the development process. The following grunt tasks are provided:
46 |
47 | #### grunt
48 |
49 | Running grunt
without any parameters, will actually execute the registered
50 | default task. This task is currently nothing more then a **lint task**, to make sure
51 | that your JavaScript code is written well.
52 |
53 | #### grunt test
54 |
55 | grunt test
executes (as you might thought) the unit tests, which are located
56 | in test/unit
. The task uses **karma** the spectacular test runner to executes
57 | the tests with the **jasmine testing framework**.
58 |
59 | #### grunt build
60 |
61 | You only have to use this task, if you want to generate a production ready build of
62 | this project. This task will also **lint**, **test** and **minify** the
63 | source. After running this task, you'll find the following files in a generated
64 | dist
folder:
65 |
66 | ````
67 | dist/angular-grunt watch
72 |
73 | This task will watch all relevant files. When it notice a change, it'll run the
74 | **lint** and **test** task. Use this task while developing on the source
75 | to make sure, everytime you make a change you get notified if your code is incosistent
76 | or doesn't pass the tests.
77 |
78 | ## Contributing/Submitting changes
79 |
80 | - Checkout a new branch based on master
and name it to what you intend to do:
81 | - Example:
82 | ````
83 | $ git checkout -b BRANCH_NAME
84 | ````
85 | - Use one branch per fix/feature
86 | - Make your changes
87 | - Make sure to provide a spec for unit tests
88 | - Run your tests with either karma start
or grunt test
89 | - When all tests pass, everything's fine
90 | - Commit your changes
91 | - Please provide a git message which explains what you've done
92 | - This repo uses [Brian's conventional-changelog task](https://github.com/btford/grunt-conventional-changelog) so please make sure your commits follow the [conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit)
93 | - Commit to the forked repository
94 | - Make a pull request
95 | - Make sure you send the PR to the canary
branch
96 | - Travis CI is watching you!
97 |
98 | If you follow these instructions, your PR will land pretty safety in the main repo!
99 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | 'use strict';
3 |
4 | require('load-grunt-tasks')(grunt);
5 | var _ = require('lodash');
6 |
7 | var karmaConfig = function(configFile, customOptions) {
8 | var options = { configFile: configFile, keepalive: true };
9 | var travisOptions = process.env.TRAVIS && { browsers: ['Firefox'], reporters: 'dots' };
10 | return _.extend(options, customOptions, travisOptions);
11 | };
12 |
13 | grunt.initConfig({
14 | pkg: grunt.file.readJSON('bower.json'),
15 | meta: {
16 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
17 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
18 | '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
19 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
20 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
21 | },
22 | watch: {
23 | scripts: {
24 | files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
25 | tasks: ['jshint', 'karma:unit']
26 | }
27 | },
28 | jshint: {
29 | all: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
30 | options: {
31 | eqeqeq: true,
32 | globals: {
33 | angular: true
34 | }
35 | }
36 | },
37 | concat: {
38 | src: {
39 | src: ['src/angular-workers.js'],
40 | dest: 'dist/angular-workers.js'
41 | }
42 | },
43 | uglify: {
44 | src: {
45 | files: {
46 | 'dist/angular-workers.min.js': '<%= concat.src.dest %>'
47 | }
48 | }
49 | },
50 | karma: {
51 | unit: {
52 | options: karmaConfig('karma.conf.js', {
53 | singleRun: true
54 | })
55 | },
56 | server: {
57 | options: karmaConfig('karma.conf.js', {
58 | singleRun: false
59 | })
60 | }
61 | },
62 | changelog: {
63 | options: {
64 | dest: 'CHANGELOG.md'
65 | }
66 | },
67 | ngmin: {
68 | src: {
69 | src: '<%= concat.src.dest %>',
70 | dest: '<%= concat.src.dest %>'
71 | }
72 | },
73 | clean: ['dist/*']
74 | });
75 |
76 | grunt.registerTask('default', ['jshint', 'karma:unit']);
77 | grunt.registerTask('test', ['karma:unit']);
78 | grunt.registerTask('test-server', ['karma:server']);
79 | grunt.registerTask('build', ['clean', 'jshint', 'karma:unit', 'concat', 'ngmin', 'uglify']);
80 | };
81 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 FredrikSandell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-workers
2 |
3 | > A wrapper for web workers in angular
4 |
5 | ###Why?
6 |
7 | Using web workers is somewhat awkward in raw Javascript. Doing it in angular applications even more so.
8 | Each web worker runs in it's own context, and this context is isolated from the angular application.
9 |
10 | ###What does angular-workers do
11 | angular-workers provides an angular service which upon request creates a web worker.
12 | The returned web worker runs it's own angular context which allows it to resolve angular dependencies.
13 |
14 | Mor information about how angular-worker work can be found in this [blog post](http://kindofcode.com/web-workers-in-angular/).
15 |
16 | ##Installation
17 |
18 | install with bower using:
19 |
20 |
21 | ```javascript
22 | bower install angular-workers
23 | ```
24 |
25 |
26 | ##How to use
27 |
28 | * Depend on the WorkerService.
29 | * Specify the URL to the file containing the angular script by invoking:
30 |
31 | ```javascript
32 | // The URL must be absolute because of the URL blob specification
33 | WorkerService.setAngularUrl(url)
34 | ```
35 |
36 | * OPTIONALLY: Specify how the web worker is to find any dependencies by invoking:
37 |
38 | ```javascript
39 | // The URL must be absolute because of the URL blob specification
40 | WorkerService.addDependency(serviceName, moduleName, url)
41 | ```
42 |
43 | * Create create a promise of an angularWorker by invoking:
44 |
45 | ```javascript
46 | var workerPromise = WorkerService.createAngularWorker(['input', 'output' /*additional optional deps*/,
47 | function(input, output /*additional optional deps*/) {
48 | // This contains the worker body.
49 | // The function must be self contained. The function body will be
50 | // converted to source and passed to the worker.
51 | // The input parameter is what will be passed to the worker when
52 | // it is executed. It must be a serializable object.
53 | // The output parameter is a promise and is what the
54 | // worker will return to the main thread.
55 | // All communication from the worker to the main thread is performed
56 | // by resolving, rejecting or notifying the output promise.
57 | // We may optionally depend on other angular services.
58 | // These services can be used just as in the main thread.
59 | // But be aware that no state changes in the angular services in the
60 | // worker are propagates to the main thread. Workers run in fully isolated
61 | // contexts. All communication must be performed through the output parameter.
62 | }]);
63 | ```
64 |
65 | * When the workerPromise resolves the worker is initialized with it's own angular context and is ready to use. Like so:
66 |
67 | ```javascript
68 | workerPromise.then(function success(angularWorker) {
69 | //The input must be serializable
70 | return angularWorker.run(inputObject);
71 | }, function error(reason) {
72 | //for some reason the worker failed to initialize
73 | //not all browsers support the HTML5 tech that is required, see below.
74 | }).then(function success(result) {
75 | //handle result
76 | }, function error(reason) {
77 | //handle error
78 | }, function notify(update) {
79 | //handle update
80 | });
81 | ```
82 |
83 | The same initialized worker can be used many times with different input.
84 |
85 | ##Requirements
86 |
87 | The browser running the angular service needs to support the following:
88 | * [Web Workers](http://caniuse.com/#feat=webworkers) (angular-workers does not use shared workers)
89 | * [Blob URLs](http://caniuse.com/#feat=bloburls), specifically [creating blobs from strings](https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL#Browser_compatibility)
90 |
91 | ##Limitations
92 |
93 | The angular-workers is a wrapper around standard web workers. So all limitations with web workers apply.
94 | * Data sent between the worker and main thread is deep cloned. (angular-workers does not use transferable objects, yet)
95 | This means transferring large object (about >20Mb, [Communicating Large Objects with Web Workers in javascript, Samuel Mendenhall](http://developerblog.redhat.com/2014/05/20/communicating-large-objects-with-web-workers-in-javascript/))
96 | will cause noticeable delays. Samuel Mendenhall recommends sending the data in chunks. This can be achieved using the notify
97 | in the angular promise.
98 | * There is no DOM in the worker. Other things are missing as well. No global "document" object. The bare minimum of these
99 | have been mocked to allow angular to start in the worker.
100 | * The web worker share no runtime data with the main thread. This is great since it prevents deadlock, starvation and many
101 | other concurrency issues. But it also means that any angular service instance upon which your worker depends is created
102 | in that worker, and not shared with the main thread. One can not communicate data between worker and main thread
103 | by using service states. All communication must be done through the input object and output promise.
104 | * Running in a separate context means the web worker does not share the cookies set in the main thread! If you depend on
105 | cookies for authentication pass these manually to the worker.
106 |
107 |
108 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Fredrik Sandell",
3 | "name": "angular-workers",
4 | "description": "Web workers wrapper for angular",
5 | "version": "1.0.4",
6 | "main": "./dist/angular-workers.js",
7 | "homepage": "http://github.com/FredrikSandell/angular-workers",
8 | "repository": {
9 | "type": "git",
10 | "url": "git://github.com/FredrikSandell/angular-workers"
11 | },
12 | "ignore": [
13 | "src",
14 | "test",
15 | ".bowerrc",
16 | ".gitignore",
17 | ".jshintrc",
18 | ".travis.yml",
19 | ".editorconfig",
20 | "bower.json",
21 | "Gruntfile.js",
22 | "package.json",
23 | "karma.conf.js"
24 | ],
25 | "dependencies": {
26 | "angular": "~1.3.*"
27 | },
28 | "devDependencies": {
29 | "angular-mocks": "~1.3.*"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/dist/angular-workers.js:
--------------------------------------------------------------------------------
1 | angular.module('FredrikSandell.worker-pool', []).service('WorkerService', [
2 | '$q',
3 | function ($q) {
4 | var that = {};
5 | var urlToAngular;
6 | var serviceToUrlMap = {};
7 | var messageIndex = 0;
8 | var indexToDeferMap = {};
9 | /*jshint laxcomma:true */
10 | /*jshint quotmark: false */
11 | var workerTemplate = [
12 | '',
13 | 'var window = self;',
14 | 'self.history = {};',
15 | 'self.Node = function () {};',
16 | 'var document = {',
17 | ' readyState: \'complete\',',
18 | ' cookie: \'\',',
19 | ' querySelector: function () {},',
20 | ' createElement: function () {',
21 | ' return {',
22 | ' pathname: \'\',',
23 | ' setAttribute: function () {}',
24 | ' };',
25 | ' }',
26 | '};',
27 | 'importScripts(\'Using webworkers with angular environment, but in an isolated context
32 |