Last active
August 29, 2015 14:10
-
-
Save ThomasBurleson/f769907846bd45f52da4 to your computer and use it in GitHub Desktop.
Enhanced version of `docSearcher` webWorker discussed in Pete Darwin's blog [AngularJS Docs Performance](http://www.bacondarwin.co.uk/angularjs-docs-performance/)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('search', []) | |
.service('docsSearch', ['$q','$rootScope','$timeout','NG_PAGES',BackgroundSearchService]); | |
/** | |
* Document search service that uses Web Workers to index | |
* and search in the background. | |
*/ | |
function BackgroundSearchService($q, $rootScope, $timeout, NG_PAGES) { | |
console.log('Using WebWorker Search Index'); | |
// Create persistent instance... | |
var searcher = new PageSearcher($q, $rootScope, NG_PAGES); | |
// API that is performant & logical for multiple, sequential queries | |
return function search(qry) { | |
return searcher.find(qry); | |
}; | |
/** | |
* Create a specialized webWorker to index pages | |
* and support multiple queries | |
* | |
* @returns {{find: function(query) }} | |
* @constructor | |
*/ | |
function PageSearcher() { | |
var worker = initialize('js/search-worker.js'); | |
// Publish simple API | |
return { | |
find: processQuery | |
}; | |
/** | |
* Add the query to the query queue | |
* @param qry | |
* @returns {*} | |
*/ | |
function processQuery(qry) { | |
var results = $q.defer(); | |
// Chain each search query... | |
worker.$queue = worker.$queue | |
.then(function startQuery() { | |
return postMessage(qry) | |
}) | |
.then(function onResponse(pages) { | |
results.resolve(pages); | |
}); | |
return results.promise; | |
} | |
/** | |
* Reset the worker.onmessage to send a message when it has | |
* completed a search query and the results are available | |
* | |
* @param qry | |
* @returns {*} | |
*/ | |
function postMessage(qry) { | |
var results = $q.defer(); | |
// Reset the callback... | |
worker.onmessage = function (oEvent) { | |
$rootScope.$apply(function () { | |
switch (oEvent.data.e) { | |
case 'query-ready': | |
var pages = oEvent.data.d.map(function (path) { | |
return NG_PAGES[path]; | |
}); | |
results.resolve(pages); | |
break; | |
default : | |
throw new Error("unknown error"); | |
} | |
}); | |
}; | |
worker.postMessage({q: qry}); | |
return results.promise; | |
} | |
/** | |
* Initialize a WebWorker and listen for `index-ready` to | |
* announce ready to run a query. | |
* | |
* NOTE: Decorate the worker with a special processing `query` queue | |
* | |
* @returns {Worker} | |
*/ | |
function initialize(path, failAfter) { | |
var startup = $q.defer(); | |
var timer = $timeout(function() { | |
startup.reject( "Worker(" + path + ") is not responding..." ); | |
}, failAfter || 5000, false); | |
try { | |
var worker = new Worker(path); | |
worker.$queue = startup.promise; | |
worker.onmessage = function (oEvent) { | |
switch (oEvent.data.e) { | |
case 'index-ready': | |
$timeout.cancel(timer); | |
startup.resolve(); | |
break; | |
} | |
}; | |
} catch( e ) { | |
$timeout.cancel(timer); | |
startup.reject( e.message ); | |
} | |
return worker; | |
} | |
} | |
} | |
Looking better and better. Now if it only had some unit tests ....
You sound just like me with the Angular Material team:
- "Hey Developer, I love those changes... but where are the tests?"
- "Wow, great fix. Did you write a test for it?"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
... I updated the
initialize()
function above.Additionally:
initialize()
supports both try/catch and timeouts for the indexing-phase of the web worker.worker.onmessage
callback is explicitly reset onceindex-ready
is handled; so the web worker is clearly partitioned into two (2) phases: indexing and query/search.worker.$queue
FIFO is never exposed/available to external consumers.