It continues execution even if the condition is true and return res.json() is executed.
_.each(rooms, function(room){
if(room.users.length == users.length) {
return res.json(room); // <-- returns but still continuous execution
}
});
Below is the error printed in console.
error: Error: Cannot write to response more than once
Do I need to do anything else?
As posted in How to break/exit from a each() function in JQuery?, you can exit each loops by returning false. Thus,
_.each(rooms, function(room){
if(room.users.length == users.length) {
res.json(room);
return false;
}
});
If that did not work and you used underscore.js, see how to break the _.each function in underscore.js which recommends using .every where return false works (instead of .each). Thus
_.every(rooms, function(room){
if(room.users.length == users.length) {
res.json(room);
return false;
}
});
you should break the loop and then res.status(200).json(room)
You could consider using a different function in the underscore/lodash api, for example, find would seem to suit what you are doing better:
var room = _.find(rooms, function(room){
return room.users.length == users.length;
});
res.json(room);
Related
I need to run a loop through multiple elements having the same CSS selector and return true if the element.text() matches with the string. If there is no match then return false at the end.
I tried something like below but it didn't work:
getProfilePresentOrNot(profileName) {
var flag = 0;
cy.get('li>div>div>span').each(($el,index,$list) => {
if ($el.text().includes(profileName)) {
flag=1;
}
});
return flag;
}
This function always returns 0 even though I can confirm that the condition in the if block satisfies.
#JeremyKahan is correct, it's like mixing synchronous and asynchronous code. The synchronous code always executes first.
Basically, you can see it by adding a couple of console.log()
function getProfilePresentOrNot(profileName) {
var flag = 0;
cy.get("li>div>div>span").each(($el, index, $list) => {
if ($el.text().includes(profileName)) {
console.log('Setting flag')
flag = 1;
}
});
console.log('Returning flag')
return flag;
}
This will print in the devtools
Returning flag
Setting flag // because cy.get(...).each(...) ran later
You could use a custom command
Cypress.Commands.add('getProfilePresentOrNot', (profileName) => {
cy.get("li>div>div>span")
.invoke('text') // all text from all spans
.then(allText => allText.includes(profileName)) // returns the result of .includes(...)
})
which must be used like this
cy.getProfilePresentOrNot('someprofilename')
.then(isPresent => { // true or false
if (isPresent) {
...
}
})
or if you are absolutely sure that all li>div>div>span are present in the page, you can still use a function but switch to synchronous Cypress code (i.e jQuery).
function getProfilePresentOrNot(profileName) {
const allText = Cypress.$("li>div>div>span").text()
return allText.includes(profileName);
}
which can be called like this
const isPresent = getProfilePresentOrNot('someprofilename')
The custom command is safest because on a production web page there are lots of things that can fail your test because the element can't be found immediately, and Cypress asynchronous commands have built-in mechanisms to avoid the problems.
"Illegal break statement" is appearing. Can anyone suggest the reason to solve it
this.selectOrganization = function() {
organizationLocator.each(function(element) {
FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg')) {
FunctionLibrary.click(element, organizationName);
break;
}
})
})
};
organizationLocator.each(function(element) {
FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg') && temp == true) {
FunctionLibrary.click(element, organizationName);
temp = false;
}
})
})
You can't break from the each method—it emulates the native forEach method's behavior, and the native forEach doesn't provide to break the loop other than throwing an exception.
See the quote from mozilla doc:
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.
Early termination may be accomplished with:
A simple loop
A for...of loop
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()
The other Array methods: every(), some(), find(), and findIndex() test the array elements with a predicate returning a truthy value to determine if further iteration is required.
But there is a solution of it which isArray.every method, which uses it's callback's return value to iterate over next element.
every executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the every method immediately returns false.
Example of Array.every method:
var orgs = ['NSO', 'CRY India', 'WHO', 'ImageResizingOrg', 'Unicef'];
var returnval = true;
orgs.every(function (text) {
if (text.includes('ImageResizingOrg')) {
//you can do anything here like firing click event as you have done in your code
returnval = false;
}
console.log(text);
return returnval;
});
Use Promise.all to combine each iteration of the for each loop and reject the promise when you wish to break out of the loop.
var promises = [];
organizationLocator.each(function(element) {
promises.push(FunctionLibrary.getText(element, organizationName).then(function(text) {
logger.info(text);
if (text.includes('ImageResizingOrg')) {
FunctionLibrary.click(element, organizationName);
return Promise.reject(false);
}
}));
});
return Promise.all(promises);
I have a promises chain and inside some points I have if-else condition like the following:
.then(function() {
if(isTrue) {
// do something returning a promise
} else {
// do nothing - just return
return;
}
})
.then(function() {
...
})
Honestly I don't like this pattern. I feel it wrong. I mean using just a plain return without anything. Do you have some idea to make look different this code?
That else { return; } part can simply be completely omitted without changing the code's meaning:
.then(function() {
if (isTrue) {
// do something returning a promise
}
})
Functions do return undefined anyway by default.
I guess you have tested the code. And recognized that this is not working like you expected. Let me explain you:
function getPromise() {
callSomeFunctionWhichReturnsPromise().then(function(result) {
return result; // You hope, that this will be logged on the console? nope, you have to do it here instead.
console.log('logged in the promise', result); // This will work
});
}
var result = getPromise();
console.log(result); // undefined!!!
you could instead do this:
function getPromise() {
return callSomeFunctionWhichReturnsPromise();
}
var result = getPromise();
result.then(console.log); // will call console.log(arguments)
Hi i am using async module of node.js for implementing a for loop asynchronously.
My question is: how to break the loop execution and get out of the loop? I tried giving return , return false but no luck.
Here is the sample code:
async.until(
function() { return goal; },
function(callback) {
async.each(_rules,
function(rule,callback) {
var outcome = true;
.... some code ....
if(changes){
console.log("hi");
return false;// HERE I NEED TO BREAK
}
else
callback();
},
function(err){ }
);
if (!changes || session.process)
goal = true;
callback();
},
function(err){ callback(session); }
);
async.until repeatedly calls function until the test returns true. So test must return true so that you exit the loop. This is opposite of async.whilst which runs repeatedly while test evaluates to be true.
async.each calls the functions in parallel so what it returns does not matter. It is not a loop which you can break, but an iterator looping over the array. Your condition to stop using async.each should be in test for async.until and you should iterate over the rules yourself.
There isn't really a "loop" as such to break out of. All your items in your collection are used in parallel
The only way to "break" the "loop" is to call the callback with an error argument. As there is nothing to stop you from putting other things in there you could hack it a little bit.
From the docs:
Note, that since this function applies the iterator to each item in
parallel there is no guarantee that the iterator functions will
complete in order.
Even if you return an error, you will still have several outstanding requests potentially so you really want to limit the amount of items you use in one go. To limit the amount of outstanding requests, you could use eachSeries or eachLimit.
For example:
async.each(_rules,
function(rule,callback) {
if(changes){
return callback({ data: 'hi'}); // stop
}
...
if(realerror){
return callback({ error: realerror}); // stop with an error
}
callback(); // continue
},
function(result){
if(!result){
return othercallback('no results');
}
// check if we have a real error:
if(result.error){
return othercallback(result.error);
}
return othercallback(null, result.data);
}
);
PS: if you're not doing async, use underscore
You have also async.detect
Returns the first value in coll that passes an async truth test. The iteratee is applied in parallel, meaning the first iteratee to return true will fire the detect callback with that result.
// asynchronous function that checks if a file exists
function fileExists(file, callback) {
fs.access(file, fs.constants.F_OK, (err) => {
callback(null, !err);
});
}
async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists,
function(err, result) {
console.log(result);
// dir1/file1.txt
// result now equals the first file in the list that exists
}
);
Having the following code:
function test(x) {
if(x=='a') return false;
return true;
}
if(y ==x) {
return test('a');
group['ids']= inputs.val();
console.log(group);
}
why return true simply breaks my code by not continuing beyond the return?
Note: I want the return test()'s answer to control if either it should continue with the code OR not
Update
I already do something like:
var response = test('b');
if (response==false) return false;
... more code here ...
But I want to avoid having to do so on every invoke of that function
Because that's what return does in almost every programming language: it
exits the function and
returns a value
If you need other code to be executed, put it before the return statement.
Edit: I saw your edit, but it doesn't change the very nature of return in that (and every) context. It will continue to stop the flow of the current scope, returning to the nearest higher scope with a value (in your case, true or false).
The keyword return, as it name suggests, returns the program flow control to the calling function and optionally sets the function's return value.
This works the same way in every C-like language.
What you probably wanted to do is a Delphi-like approach, where the keyword Result works differently - it just sets the return value that will be used when the function terminates, but does not immediately terminate the function.
function() {
var result = someDefaultValue;
if (someCondition)
result = otherValue;
if (otherCondition)
result = yetAnotherValue;
return result;
}
try putting return at the end because return true will break the execution and nothing will execute after that
When a return statement executes, the execution of the current function ends, and control of the program is returned to the context that invoked the function. Anything after a return statement will not be executed.
The return keyword causes a function to end ('return') when the interpreter reaches that keyword and does not continue to process anything after the return statement (in that same function).
You could rewrite what you have:
group['ids']= inputs.val();
console.log(group);
return true;
I typically find out which scenarios are bad/errors and return false; out of them, THEN continue on to the code which is correct.
function Testmcdooder (test) {
if (test === false) {
// just exit up here
return false;
}
// now all of this code will run only if we're fine
group['ids']= inputs.val();
console.log(group);
}
The return statement exists from the function. I think that you rather want an if statement:
if (y == x) {
if (test('a')) {
group['ids']= inputs.val();
console.log(group);
}
}
If you also want to return the value after determining if the other statemens should run:
if (y == x) {
if (test('a')) {
group['ids']= inputs.val();
console.log(group);
return true;
} else {
return false;
}
}
Alternatively:
if (y == x) {
var cond = test('a');
if (cond) {
group['ids']= inputs.val();
console.log(group);
}
return cond;
}