I am handling very hight dataset with type arry. While iterating through this arrays my application gets performance hit. I want to use webworkers which will perform manipulation operations on huge array and it will directly return the processed dataset back to application.web
Take a look at https://github.com/vkiryukhin/ng-vkthread I develop it exactly for such kind of tasks. It let you easily export function in a thread, execute it and get result in UI. Even more: you can download data directly in a thread rather than transfer it from UI to a thread.
the very basic usage is:
/* function to execute in a thread */
function foo(n, m){
return n + m;
}
/* create an object, which you pass to vkThread as an argument*/
var param = {
fn: foo // <-- function to execute
args: [1, 2] // <-- arguments for this function
};
/* run thread */
vkThread.exec(param).then(
function (data) {
console.log(data); // <-- thread returns 3
},
function(err) {
alert(err); // <-- thread returns error message
}
);
Doc and examples: http://www.eslinstructor.net/ng-vkthread/demo/
Related
I am facing a weird case, I am using google directionsService.route. but it doesn’t sync well. Here is my code:
angular.forEach(requestArray, function(v, i) {
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
});
});
As you can see, I am looping the location Array into the route. every time I fire the function, it will go through the requestArray first, (if we make a breakpoint on the line (var googleLeg = result.routes[0].legs[0]), it doesn’t reach there until it goes through all the requestArray.(i from 0 - length); then it will have the second loop for directionsService.route( at this time, it will reach to line(var googleLeg = result.routes[0].legs[0]); Any idea about this?
Essentially your problem is that calling a google service is an asynchronous call, and you are not guaranteed when the callback will execute. If you need to process requestArray synchronously, here is what you can do:
function start() {
// create a copy of request array
var stuff = [].slice.call(requestArray);
function continueSync() {
// stop the recursion if we have nothing left to process
if (!stuff || stuff.length == 0) return;
// grab the first item off of the stuff queue
v = stuff[0];
stuff = stuff.slice(1);
// call to google
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
// now continue processing the rest of the stuff queue through tail recursion
continueSync();
});
}
// kick off our recursive processing
continueSync();
}
your problem is that calling a google service is an asynchronous call, you could prove to generate threads
I am new to using of web worker API in angularjs, I want to know the flow sequence for the web worker in angularjs, i.e., should I write services, then use them in controller and so on.. please i want to know flow sequence...
Yes, the question is very general.
But for those, who need to implement a particular task in angular environment I can recommend plugin https://github.com/vkiryukhin/ng-vkthread It let you easily export a function in a thread, execute it and get result in UI.
something like this:
/* function to execute in a thread */
function foo(n, m){
return n + m;
}
/* create an object, which you pass to vkThread as an argument*/
var param = {
fn: foo // <-- function to execute
args: [1, 2] // <-- arguments for this function
};
/* run thread */
vkThread.exec(param).then(
function (data) {
console.log(data); // <-- thread returns 3
},
function(err) {
alert(err); // <-- thread returns error message
}
);
see live demo at: http://www.eslinstructor.net/ng-vkthread/demo/
contact me on github if you have any questions
I have this JSON example:
$scope.channels = {
"ch1": {
id: "ch1",
data: {}
},
"ch2": {
id: "ch2",
data: {}
}
};
QUE 1
How do I update the data: {} part with the dynamic key ?
something like:
for ( var c in $scope.channels ) {
$http.get(JSON_PATH + c + '.json').then(function(res){
// DOES NOT WORK
$scope.channels[c]["data"] = res.data;
// ALSO DOES NOT WORK
var section = $scope.channels[c];
section.data = res.data;
$scope.channels[c] = section;
});
}
The result of $scope.channels is now to have a new section called "data" instead of being under the key == "ch1" (i.e).
In addition, Sublime Text 3 also gives a warning which I'm not sure why? ( it's not like I'm using this or something:
181 don't make functions within a loop
QUE 2
I solved the above problem by actually create an external function and call it within the loop.
So I was wondering why the above code in Que1 doesn't work, while this does:
function load_data(id) {
$http.get(JSON_PATH + c + '.json').then(function(res){
var section = $scope.channels[c];
var section.data = res.data;
$scope.channels[c] = section; // WORK
});
}
for ( var c in $scope.channels ) {
load_data(c);
}
In Que 1 the for loop has continued it's cycle while the $http method is asyncronously processing. The "c" variable has lost it's original context and value. I believe it is destroyed once the for loop completes.
In Que 2, "c" is now "id", and has been passed in as a static value that will continue to be available to anything inside the function closure regardless of asyncronous activity. The function makes a reference to "c" and ceases to care whether the loop destroys it or not.
This has to do with function closures, and will need someone with a better understanding to explain it in detail.
You should change "c" to "id" in Que 2 though, inside your function.
Also, as a semi-related side note, if you are going to loop a series of $http calls, you might want to look up the $q.all documentation and read about how to build promise arrays where you can detect resolution of all calls rather than just individual calls. It can be quite useful.
I am trying to make an array of integers with data I have stored on an online database (Parse). I know for a fact that I am receiving the data and that my variable is storing that data. I also know for a fact that the data value is being added as when I print out the size of the array under my append line, the size constantly increases until it reaches the size of my database (90). However, when I print the size of the array at the end of the method or in my constructor, I get a value of 0. I have a feeling that this problem is happening because of the "self" keyword but I am not sure how to get around it. My end goal is store all the values from the database into an array that I create and can globally access.
Here is the code:
import Foundation
class DataLoader
{
var allData: [Int] = []
init()
{
allData = []
generateAllData()
println(allData.count)
}
private func generateAllData()
{
var tempVal: Int = 0
var tempArray: [Int] = []
Parse.setApplicationId("CENSORED FOR PRIVACY REASONS", clientKey: "CENSORED FOR PRIVACY REASONS")
var query = PFQuery(className: "Snapshot")
query.selectKeys(["objectID"])
query.findObjectsInBackgroundWithBlock
{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil
{
for obj in objects
{
var temp: String = obj.objectId
var newQuery = PFQuery(className: "Data")
newQuery.getObjectInBackgroundWithId(temp)
{
(dataValue: PFObject!, error: NSError!) -> Void in
if error == nil && dataValue != nil
{
tempVal = dataValue["Year"].integerValue
}
else
{
println(error)
}
}
self.allData.append(tempVal)
println(self.allData.count)
}
}
}
println(allData.count)
}
}
The problem is that the println's at the end of the method and the end of the init are happening while the background operation is still getting the data.
When you call "query.findObjectsInBackgroundWithBlock", it will go off into the background and get the data. But that does not block the next line from being called and it does not stop the function returning.
I suggest you add a callback or delegate method so that the rest of your code knows when the data has completely downloaded.
And you use of "self" is correct. Inside a block, you have to provide that context.
Update:
Adding more info about blocks and callbacks.
When you are using a block, the code after the block continues on without waiting for the block to complete. So a good way to know when the block has finished it to send a callback function as one of the parameters to the function containing the block. Once the block has completed, it can use the callback function to report back.
As a shorter example than your code, have a look at this animation function:
doSomeAnimation() // call the function below
func doSomeAnimation() {
println("Starting doSomeAnimation")
UIView.animateWithDuration(2.0,
animations: { () -> Void in
// animate something here
self.alphaButton.alpha = 1.0
}) { (animationDone) -> Void in
// animation over
println("Animation complete")
}
println("Ending doSomeAnimation")
}
You will see it contains 3 println() statements and the order in which they appear may surprise you:
Starting doSomeAnimation
Ending doSomeAnimation
Animation complete
So the doSomeAnimation() function is over long before the animation has completed. In this trivial example, that doesn't matter, but what if you need to know before the rest of your code could proceed?
One solution is to send a callback function to the function with the block. Here is the previous example with a callback in place:
doSomeAnimation() { (complete : Bool) in
println("Animation callback")
}
func doSomeAnimation(callback : ( Bool ) -> Void) {
println("Starting doSomeAnimation")
UIView.animateWithDuration(2.0,
animations: { () -> Void in
// animate something here
self.alphaButton.alpha = 1.0
}) { (animationDone) -> Void in
// animation over
println("Animation complete")
callback(animationDone)
}
println("Ending doSomeAnimation")
}
So the doSomeAnimation() function is called, but it is provided with a function as its parameter. It performs the animation and when the animation has finished, it uses this supplied callback function to report back to the caller.
And now the println() statements show as follows:
Starting doSomeAnimation
Ending doSomeAnimation
Animation complete
Animation callback
Hopefully this makes it clearer, both what the issue is an a possible solution.
I currently have 2 pages, page1.php and page2.php, each of the pages uses a controller that completes its own functions etc.
However there are tabs within the pages that are exactly the same that gets a promise from a factory within the module. The lists are exactly the same except for querying on different IDs. For example both controllers have this:
pageListFactory.getData().then(function (result) {
$scope.BasicItems = result; $scope.basicItemsList = [];
angular.forEach($scope.BasicItems, function (BasicItem) {
angular.forEach(BasicItem['SomeInnerArray'], function (BasicSomeInnerItem) {
if (BasicSomeInnerItem == VARIABLE_THAT_CHANGES) {
$scope.basicItemsList.push({
ID: BasicItem.ID, Title: BasicItem.Title
});
}
});
});
});
So this code is used, and the VARIABLE_THAT_CHANGES is just what changes each time. However as I said it is used on multiple pages, is there a way to create just one function call and then each page just can call a specific bit and send the variable with it?
I tried using $rootScope but of course this just clogs and slows, and I'm not exactly happy on constantly using $rootScope to pass the $scope.basicItemsList around as the list could get quite big.
So is there any way to reuse this code without just copying and pasting it into each controller?
Sure you can re-use it...
Convert the factory to a service, its basically a name change, create a local variable to store the data, update the data on first call, and then grab the data if it exists on the second call.
.service('myService', ... stuff ... { // I suggest using a service, as I don't know if a factory would act as a singleton
var myData = null;
return {
getData: function(){
if(myData != null)
return myData; // returns data
else {
return $http()... // ajax call returns promise
}
},
setData: function(dataToSet){
myData = dataToSet;
}
}
Then your controllers:
//controller 1
var promiseOrData = pageListFactory.getData();
if(promiseOrData instanceOf Array){ // or whatever data you expect
$scope.BasicItems = promiseOrData;
....
}
else { // should be a promise
promiseOrData.then(function (result) {
pageListFactory.setData(result); // set the data once you get it.
$scope.BasicItems = result; $scope.basicItemsList = [];
....
}
}
In controller 2 you only need to get the data as the returned data will be an array, not a promise
On top of all this, write a directive which will process the data when you pass it along, then you can pass the variableThatChanges and have the directive take care of it.
Use services and write the function in that service and pass the variable VARIABLE_THAT_CHANGES into it. By this you can reuse the code.