I read somewhere in the past that angular.foreach is asynchronous unlike looping over arrays which is synchronous. For a long time I was taking into account this and doing the necessary to avoid executing the code which comes after the loop before it's finishes all its iterations (by wrapping the angular.foreach inside an anonymous JavaScript function which calls a callback which will be executed once the loop finishes all iterations).
(function(callback){
angular.foreach(..)
callback();
})(callback)
But I had a conversation with a collegue who didn't agree that angular.foreach is asynchronous and I also couldn't find that information again which makes me confused now.
no. Take a look at the docs
Furthermore your code wouldn't work if foreach would be asynchronous.
If foreach would be async, the callback would be called immediately after calling foreach and foreach would be put onto the eventqueue which would execute it some time in the future.
Javascripts concurrency model does not have threads but instead uses an eventloop. This means every async operation is pushed onto the eventqueue and executed later.
Have a look into the MDN
There may be a scenario where you want to make code behave asynchronously.
I had a scenario where I used local storage to store an ad-hoc user selected collection of jobs that I wanted to perform the same operation on.
I had a web service call to convert a list of job names into a returned a collection of job objects. I initially tried using a
foreach loop inside the subscribe pf the service layer, that operated on the results.
Then I tried calling another method within the foreach loop that as it performed the operations removed the job name from local storage when the operation posted to the web service correctly.
The problem was on the second iteration I read the collection of names from local storage again - before the set to remove had completed.
There was a lot of manipulation of the job and object properties to create the parameters passed on the function call, so I ended up refactoring the code, creating a value object interface and stored the information in a value object array for the whole job collection I had returned. I included the index of the job too in the value object.
I introduced a BehaviourSubject property to the class.
During the restructuring, I just added an entry to the value object array collection within the forEach loop instead. At the end of the loop. I sent next(0) to the BehaviourSubject to start the ball rolling.
Each time a job name was removed from local storage, I converted service to return a Promise.
Then in the code after the service was called I put this code in the then part, behaviour subject.next(index from value object +1)
In the initialisation I set the behaviour subject up with a -1 value..
Then in the subscription to the BehaviourSubject class I ignored -1,
And when the index +1 was > length of value object collection called completion routine - which bounce app back to prior page.
When the index was between 0 and 1 less than collection size, I just called the method that had originally been in the forEach loop with the value object entry with the value object match the index of the behaviour subject.
By doing this I had converted the behaviour of the forEach into something asynchronous.
Related
From a soap XML response I need to get all the occurrences of an id (This part already done using Match No being set to -1 in Regex extractor).
And then I need to send these ids to a subsequent request. That is, the request needs to be fired as many times as of the total number of occurrences of the id, we can call it as ID_matchNr. (This is the total occurrences I got from the Regex extractor).
I used a while loop and a counter. The while loop works until the ID_matchNr, but it doesn't stop there, that while loop is infinite. How to fix this?
My counter's reference name is count and the field name in my request is ${__V(ID_${count})}. And while loop's condition is ${count}<=${ID_matchNr}. I also tried using a beanshell to save the ID_matchNr to another variable and then use it in while condition instead of directly using ID_matchNr. Still running infinitely.
Have you considered using ForEach Controller?
Given you have JMeter Variables in form of:
ID_1=foo
ID_2=bar
ID_3=baz
ID_matchNr=3
Add ForEach Controller to your Test Plan and configure it like:
And put the "subsequent" sampler as a child of the ForEach Controller and refer the generated subsequent ID value as ${CURRENT_ID} where required
More information on the concept with the real-life example: Using Regular Expressions in JMeter
I want to create an experiment in PsychoPy Builder that conditionally shows a second routine to participants based on their keyboard response.
In the task, I have a loop that first goes through a routine where participants have three options to respond ('left','right','down') and only if they select 'left', regardless of the correct answer, should they see a second routine that asks a follow-up question to respond to. The loop should then restart with routine 1 each time.
I've tried using bits of code in the "begin experiment" section as such:
if response.key=='left':
continueRoutine=True
elif response.key!='left':
continueRoutine=False
But here I get an error saying response.key is not defined.
Assuming your keyboard component is actually called response, the attribute you are looking for is called response.keys. It is pluralised as it returns a list rather than a single value. This is because it is capable of storing multiple keypresses. Even if you only specify a single response, it will still be returned as a list containing just that single response (e.g. ['left'] rather than 'left'). So you either need to extract just one element from that list (e.g. response.keys[0]) and test against that, or use a construction like if 'left' in response.keys to check inside the list.
Secondly, you don't need to have a check that assigns True to continueRoutine, as it defaults to being True at the beginning of a routine. So it is only setting it to False that results in any action. So you could simply do something like this:
if not 'left' in response.keys:
continueRoutine = False
Lastly, for PsychoPy-specific questions, you might get better support via the dedicated forum at https://discourse.psychopy.org as it allows for more to-and-fro discussion than the single question/answer structure here at SO.
I have an array of observables. Each of them will make a http call to a REST endpoint and return a result so I can update the UI.
I am using zip to run them all like this:
Observable.zip(allTransactions).subscribe(result=> {blab});
In subscribe, I update a page-level collection, so UI gets updated via 2-way binding (angular).
however, there are a few problems:
1) when I construct each observable in the array, I added .delay(1000) to it, so I expect each run will delay at least 1 second to the previous one. In fact, that's not true. Based on my log, it seems all those transactions were fired at the same time. But the subscribe was delayed on second. I really need them run in sequence, as the order I setup the array, because I have some dependency in those transactions. Running all together won't work for me.
2) zip doesn't seem to guarantee to bring back my results in ordered. So my UI is totally in random ordered. Because I was doing this.items.push(result), where items is a variable being bound to the UI.
I am currently trying to merge all the transactions and add an empty observable with delay between every 2 transactions (still working on it).
Can anyone provide any suggestion what other alternatives I can do? or a better way I can try?
Thanks
1) You are correct that adding .delay(1000) to all observables will not make them wait for the previous one. The delay operator will delay the execution from the moment you subscribe to them, and since you subscribe to them all at the same time and delay them for the same amount of time, they will all execute at the same time.
If you want to execute the observable in sequence, and wait for one to finish before proceeding to the next then use the flatMap operator:
obs1.get()
// First call
.flatMap(response1 => {
return obs2.get(response1.something);
})
.subscribe(response2 => {
// Result from second call
});
2) Looking at the zip documentation the result should return in an ordered list:
Merges the specified observable sequences or Promises into one
observable sequence by using the selector function whenever all of the
observable sequences have produced an element at a corresponding
index. If the result selector function is omitted, a list with the
elements of the observable sequences at corresponding indexes will be
yielded.
But as you have noted: the calls are all executed simultaneously and one observable does not wait for the next one before starting.
So the call:
Observable.zip(obs1, obs2, obs3).subscribe(result => console.log(result));
Will log:
[response1, response2, response3]
I'm trying to use ng-grid with a sliding window of 100 records. The data is coming in realtime via signalR and every message trigger the following method:
onNewTrades(records) {
console.log("onNewRecord", records);
if (connectionStopped) return;
for (var i = 0; i < records.length; i++) {
if ($scope.recordsData.length > maxRecordsInTable)
$scope.recordsData.pop();
$scope.recordsData.unshift({
t: new Date(records[i][0]),
p: records[i][1],
a: records[i][2]
});
}
}
I have a threshold of 100 maxRecordsInTable before I start popping items off the end (before adding the new message to the front)
However, when it reaches my threshold the table simple stops updating. Strangely though, if I set a breakpoint on unshift(), the table does update with every "continue".
I suspect it's some kind of angular timing issue? I tried using $timeout()
Or may when I pop() and unshift() at the same time it doesn't pick up a change in the array? I tried using $apply() (error already in digest cycle)
There are a few things that could be happening here.
First of all, if onNewTrade is using an external, non-angular, library making xhr requests outside of angular's framework (i.e. not using $http or $resource), you have to call $scope.$apply(function(){ }) around the code you want the scope's digest to know about. That part's not clear from what you've provided. edit: Read more about when to use $scope.$apply
Second, angular's digest phase does a minimum of two passes (first to make changes, second to make sure there are no more changes). It does at most 10 passes by default. If angular evaluates the scope 10 times and it is not consistent, it gives up. see documentation. It does this because you can have multiple watch functions where one watch affects the scope higher in the hierarchy, which makes changes and affects the same watch.. basically causing an evented infinite loop. Do you see a console error about '10 $digest iterations, aborting!' or something similar?
There are a couple of other questionable things:
is onNewRecord asynchronous? If so, I would doubt connectionStopped is being done correctly. You could be returning early. Because you say a breakpoint shows values on unshift, its probably not the cause of this issue (and most likely missing $scope.$apply is the problem), but I'd rethink this code.
Your function is onNewTrade(records), but you log onNewRecord(record). If you have nested variables here, make sure you haven't excluded code that may contain typos (e.g. record instead of records). You might be working on an unexpected object.
How to do a basic loop through different properties for a fixed set of controllers? Loop controller runs a set group a certain number of times, does not use properties though.
I can do modules, and set the values to properties for multi thread group usage, but how to pass the next iteration of the property, and run the loop again?
property x
do module (points to controllers)
next property
Say I have a list of 44 characters, and I want to loop through those characters in a ${name} while I'm doing a test. I'd very much not like to build 44 sets of controllers for one character change.
Please Note I cannot add extra files to my computer. It has to work via the stock available controllers. I'm using Jmeter 2.4 r961953
Thanks
I will elaborate slightly more about the BeanShell method. My assumption is that you'd like to do it within one User Thread, if so my proposal would be:
Create a Loop Controller.
Logic Controller->Loop Controller
Inside Loop Controller add following entries:
Config Element -> Counter
Preprocessors -> BeanShell preprocessor
Sampler -> yourSampler
The Counter element will be used as an index that will be used to choose valid value from our array, hence we need to specify a Reference Name for the Counter - let's say that it will be loopCounter.
Now we have to switch to BeanShell preprocessor and define the array of values. A great thing is that we have vars variable available and it gives us CRUD access to variables used in the scenario:
String[] varArray = {"Value1", "Value2"};
idx = Integer.parseInt(vars.get("loopCounter"))-1;
vars.put("myVariable", varArray[idx]);
And for the final step, inside mySampler we can use a variable in a regular JMeter way : ${myVariable}
JMeter API can be very helpfull if you want a more sophisticated solution.
There are a handful of different ways to loop through different values without adding external files:
Use beanshell controller, and write javascript to set your variable
Use a counter to increment by one
Use User Parameters
You can set it up so each loop gets a different value.
Check out the various configuration controllers to find one that works best for you.
EDIT:
I meant user parameters, not user define variables.
User Parameter
You'd need one row per variable with 44 columns. Sorry for the confusion.
User Parameter Structure
test plan
- Thread Group looped 44 times
-- User parameter
-- Request
Beanshell Method
Alternately, you could do an array in javascript in connection with a counter. The Beanshell samplers have access to Jmeter variables and properties, allowing the beanshell sampler to read the counter value. This may be a faster, cleaner way then using User Parameters.
Beanshell structure
test plan
- Thread Group looped 44 times
-- Counter
-- Request
---- Beanshell pre-processor
Beanshell Pseudo code would be
def counter = value of Jmeter Counter
def array = array of values
declare the variable "sampler_value" to be used by sampler
def sampler_value = array # counter
Counter with CharAt function
If you only need to generate characters, you could use the javascript function to utilize the function charAt, using the value from the Counter. Basic structure would be:
test plan
- Thread Group looped 44 times
-- Counter
-- Request
with the request using something like ${__javaScript(charAt(${counter})) as the parameter value. You may have to use JEXL instead of javaScript or evalVar/V/eval inside the charAt function.