Terminate Javascript without error / exception - javascript

I need to terminate the javascript from a function so that it doesn't execute the next block of codes and other functions called by the script, which follows the current function.
I found this existing question in SO : How to terminate the script in Javascript , where the solution is given as to trigger an error / exception which will terminate the script immediately.
But my case is different because, My purpose of terminating the script is to prevent an error which will come from the next functions, if the current function doesn't stop execution of the script. So, triggering another error to prevent an error is no way solving my purpose!
So, is there any other way of terminating the javascript instead of throwing an error / exception?
Please read my question properly before marking as duplicate, I have already explained why it doesn't solve my problem with the question I referred!.

Since you're inside a function, just return.
Reading into your question a little more that it doesn't execute "other functions called by the script", you should return a boolean. For example, return false if you don't want the rest called, then wrap the remaining statements in an if:
function Foo() {
if (weAreInLotsOfTrouble) {
return false;
}
return true;
}
DoSomething();
DoSomethingElse();
if (Foo()) {
DoSomethingDangerous();
}

Try using jQuery.Callbacks() with parameter "stopOnFalse" ; jQuery.when() , jQuery .then()
var callbacks = $.Callbacks("stopOnFalse");
function a(msg) {
var msg = msg || "a";
console.log(msg);
return msg
}
// stop callbacks here
function b() {
var msg = false;
console.log(msg)
return msg
}
// `c` should not be called
function c() {
var msg = new Error("def");
console.log(msg)
return msg
}
callbacks.add(a,b,c);
$.when(callbacks.fire())
.then(function(cb) {
// `c` : `Error`
if (cb.has(c)) {
console.log("callbacks has `c`"
, cb.has(c));
// remove `c`
cb.remove(c);
console.log(cb.has(c));
// empty `callbacks`
cb.empty();
// do other stuff
cb.add(a);
cb.fire("complete")
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

Related

Access and modify website variables using Javascript [duplicate]

I have a click event that is triggered from another place automatically for the first time. My problem is that it runs too soon, since the required variables are still being defined by Flash and web services. So right now I have:
(function ($) {
$(window).load(function(){
setTimeout(function(){
$('a.play').trigger("click");
}, 5000);
});
})(jQuery);
The problem is that 5 seconds for a person with a slow internet connection could be too fast and vice versa, for a person with a fast internet connection, it's too slow.
So how should I do the delay or timeout until someVariable is defined?
The following will keep looking for someVariable until it is found. It checks every 0.25 seconds.
function waitForElement(){
if(typeof someVariable !== "undefined"){
//variable exists, do what you want
}
else{
setTimeout(waitForElement, 250);
}
}
async, await implementation, improvement over #Toprak's answer
(async() => {
console.log("waiting for variable");
while(!window.hasOwnProperty("myVar")) // define the condition as you like
await new Promise(resolve => setTimeout(resolve, 1000));
console.log("variable is defined");
})();
console.log("above code doesn't block main function stack");
After revisiting the OP's question. There is actually a better way to implement what was intended: "variable set callback". Although the below code only works if the desired variable is encapsulated by an object (or window) instead of declared by let or var (I left the first answer because I was just doing improvement over existing answers without actually reading the original question):
let obj = encapsulatedObject || window;
Object.defineProperty(obj, "myVar", {
configurable: true,
set(v){
Object.defineProperty(obj, "myVar", {
configurable: true, enumerable: true, writable: true, value: v });
console.log("window.myVar is defined");
}
});
see Object.defineProperty
or use es6 proxy (which is probably overkill)
If you are looking for more:
/**
* combining the two as suggested by #Emmanuel Mahuni,
* and showing an alternative to handle defineProperty setter and getter
*/
let obj = {} || window;
(async() => {
let _foo = await new Promise(res => {
Object.defineProperty(obj, "foo", { set: res });
});
console.log("obj.foo is defined with value:", _foo);
})();
/*
IMPORTANT: note that obj.foo is still undefined
the reason is out of scope of this question/answer
take a research of Object.defineProperty to see more
*/
// TEST CODE
console.log("test start");
setTimeout(async () => {
console.log("about to assign obj.foo");
obj.foo = "Hello World!";
// try uncomment the following line and compare the output
// await new Promise(res => setTimeout(res));
console.log("finished assigning obj.foo");
console.log("value of obj.foo:", obj.foo); // undefined
// console: obj.foo is defined with value: Hello World!
}, 2000);
I would prefer this code:
function checkVariable() {
if (variableLoaded == true) {
// Here is your next action
}
}
setTimeout(checkVariable, 1000);
I prefer something simple like this:
function waitFor(variable, callback) {
var interval = setInterval(function() {
if (window[variable]) {
clearInterval(interval);
callback();
}
}, 200);
}
And then to use it with your example variable of someVariable:
waitFor('someVariable', function() {
// do something here now that someVariable is defined
});
Note that there are various tweaks you can do. In the above setInterval call, I've passed 200 as how often the interval function should run. There is also an inherent delay of that amount of time (~200ms) before the variable is checked for -- in some cases, it's nice to check for it right away so there is no delay.
With Ecma Script 2017 You can use async-await and while together to do that
And while will not crash or lock the program even variable never be true
//First define some delay function which is called from async function
function __delay__(timer) {
return new Promise(resolve => {
timer = timer || 2000;
setTimeout(function () {
resolve();
}, timer);
});
};
//Then Declare Some Variable Global or In Scope
//Depends on you
let Variable = false;
//And define what ever you want with async fuction
async function some() {
while (!Variable)
await __delay__(1000);
//...code here because when Variable = true this function will
};
////////////////////////////////////////////////////////////
//In Your Case
//1.Define Global Variable For Check Statement
//2.Convert function to async like below
var isContinue = false;
setTimeout(async function () {
//STOPT THE FUNCTION UNTIL CONDITION IS CORRECT
while (!isContinue)
await __delay__(1000);
//WHEN CONDITION IS CORRECT THEN TRIGGER WILL CLICKED
$('a.play').trigger("click");
}, 1);
/////////////////////////////////////////////////////////////
Also you don't have to use setTimeout in this case just make ready function asynchronous...
You can use this:
var refreshIntervalId = null;
refreshIntervalId = setInterval(checkIfVariableIsSet, 1000);
var checkIfVariableIsSet = function()
{
if(typeof someVariable !== 'undefined'){
$('a.play').trigger("click");
clearInterval(refreshIntervalId);
}
};
Here's an example where all the logic for waiting until the variable is set gets deferred to a function which then invokes a callback that does everything else the program needs to do - if you need to load variables before doing anything else, this feels like a neat-ish way to do it, so you're separating the variable loading from everything else, while still ensuring 'everything else' is essentially a callback.
var loadUser = function(everythingElse){
var interval = setInterval(function(){
if(typeof CurrentUser.name !== 'undefined'){
$scope.username = CurrentUser.name;
clearInterval(interval);
everythingElse();
}
},1);
};
loadUser(function(){
//everything else
});
Instead of using the windows load event use the ready event on the document.
$(document).ready(function(){[...]});
This should fire when everything in the DOM is ready to go, including media content fully loaded.
Shorter way:
var queue = function (args){
typeof variableToCheck !== "undefined"? doSomething(args) : setTimeout(function () {queue(args)}, 2000);
};
You can also pass arguments
I have upvoted #dnuttle's answer, but ended up using the following strategy:
// On doc ready for modern browsers
document.addEventListener('DOMContentLoaded', (e) => {
// Scope all logic related to what you want to achieve by using a function
const waitForMyFunction = () => {
// Use a timeout id to identify your process and purge it when it's no longer needed
let timeoutID;
// Check if your function is defined, in this case by checking its type
if (typeof myFunction === 'function') {
// We no longer need to wait, purge the timeout id
window.clearTimeout(timeoutID);
// 'myFunction' is defined, invoke it with parameters, if any
myFunction('param1', 'param2');
} else {
// 'myFunction' is undefined, try again in 0.25 secs
timeoutID = window.setTimeout(waitForMyFunction, 250);
}
};
// Initialize
waitForMyFunction();
});
It is tested and working! ;)
Gist: https://gist.github.com/dreamyguy/f319f0b2bffb1f812cf8b7cae4abb47c
Object.defineProperty(window, 'propertyName', {
set: value => {
this._value = value;
// someAction();
},
get: () => this._value
});
or even if you just want this property to be passed as an argument to a function and don't need it to be defined on a global object:
Object.defineProperty(window, 'propertyName', { set: value => someAction(value) })
However, since in your example you seem to want to perform an action upon creation of a node, I would suggest you take a look at MutationObservers.
I have an adaptation of the answer by #dnuttle that I would suggest using.
The advantage of using a try-catch block is that if any part of the code you are trying to execute fails, the whole block fails. I find this useful because it gives you a kind of transaction; everything or nothing gets done.
You should never write code that could end up in an endless loop due to external factors. This is exactly what would happen if you were waiting for a response from an ajax request and the server doesn't respond. I think it's good practice to have a timeout for any questionable loops.
let time = 0; // Used to keep track of how long the loop runs
function waitForElement() {
try {
// I'm testing for an element, but this condition can be
// any reasonable condition
if (document.getElementById('test') === null) {
throw 'error';
}
// This is where you can do something with your variable
// document.getElementById('test').addEventListener....
// or call a function that uses your value
} catch (error) {
// Loop stops executing if not successful within about 5 seconds
if (time > 5000) {
// I return false on failure so I can easily check for failure
return false;
} else {
// Increment the time and call the function again
time += 250;
setTimeout(waitForElement, 250);
}
}
}
// Call the function after the definition, ensures that time is set
waitForElement();
You could have Flash call the function when it's done. I'm not sure what you mean by web services. I assume you have JavaScript code calling web services via Ajax, in which case you would know when they terminate. In the worst case, you could do a looping setTimeout that would check every 100 ms or so.
And the check for whether or not a variable is defined can be just if (myVariable) or safer: if(typeof myVariable == "undefined")
Very late to the party but I want to supply a more modern solution to any future developers looking at this question. It's based off of Toprak's answer but simplified to make it clearer as to what is happening.
<div>Result: <span id="result"></span></div>
<script>
var output = null;
// Define an asynchronous function which will not block where it is called.
async function test(){
// Create a promise with the await operator which instructs the async function to wait for the promise to complete.
await new Promise(function(resolve, reject){
// Execute the code that needs to be completed.
// In this case it is a timeout that takes 2 seconds before returning a result.
setTimeout(function(){
// Just call resolve() with the result wherever the code completes.
resolve("success output");
}, 2000);
// Just for reference, an 'error' has been included.
// It has a chance to occur before resolve() is called in this case, but normally it would only be used when your code fails.
setTimeout(function(){
// Use reject() if your code isn't successful.
reject("error output");
}, Math.random() * 4000);
})
.then(function(result){
// The result variable comes from the first argument of resolve().
output = result;
})
.catch(function(error){
// The error variable comes from the first argument of reject().
// Catch will also catch any unexpected errors that occur during execution.
// In this case, the output variable will be set to either of those results.
if (error) output = error;
});
// Set the content of the result span to output after the promise returns.
document.querySelector("#result").innerHTML = output;
}
// Execute the test async function.
test();
// Executes immediately after test is called.
document.querySelector("#result").innerHTML = "nothing yet";
</script>
Here's the code without comments for easy visual understanding.
var output = null;
async function test(){
await new Promise(function(resolve, reject){
setTimeout(function(){
resolve("success output");
}, 2000);
setTimeout(function(){
reject("error output");
}, Math.random() * 4000);
})
.then(function(result){
output = result;
})
.catch(function(error){
if (error) output = error;
});
document.querySelector("#result").innerHTML = output;
}
test();
document.querySelector("#result").innerHTML = "nothing yet";
On a final note, according to MDN, Promises are supported on all modern browsers with Internet Explorer being the only exception. This compatibility information is also supported by caniuse. However with Bootstrap 5 dropping support for Internet Explorer, and the new Edge based on webkit, it is unlikely to be an issue for most developers.
while (typeof myVar == void(0)) {
if ( typeof myVar != void(0)) {
console.log(myVar);
}
}
This makes use of the typeof operator which only returns undefined if variable is not declared yet. Should be applicable in every type of javascript.

How can I stop all code execution in javascript?

Let's say I have this code:
var myVar = 0;
function myFunctionOne() {
myVar = myVar + 2;
if(myVar <= 3) {
alert("all is good");
} else {
showError(myVar);
}
}
function myFunctionTwo() {
myVar = myVar + 2;
if(myVar <= 3) {
alert("all is good");
} else {
showError(myVar);
}
}
function myFunctionThree() {
//This should never run....
myVar = myVar + 2;
if(myVar <= 3) {
alert("all is good");
} else {
showError(myVar);
}
}
function showError(myVar) {
alert("Error Var is larger than 3. Var is" + myVar);
return false;
//This doesn't seem to stop anything
}
myFunctionOne();
myFunctionTwo();
myFunctionThree();
Here is also the fiddle: http://jsfiddle.net/dzjk44Lr/
What can I put inside my showError() function, that will kill any subsequent function calls? In this example, myFunctionThree(); should never run.
I know this is a simple example, but I'm trying to get my head around the module pattern, and in my module I have a lot of functions that delegate work, and modify variables. So if one function fails, or is given an illegal variable, I want everything to stop and show the user an error. Because if there was an error in myFunctionOne() for example, there is no point in continuing to execute any of the other code.
I guess, I'm looking for something like the php exit() function.
Any advice about how to do this, or how I should do it differently would be greatly appreciated.
You can throw an error:
throw new Error("Error Var is larger than 3. Var is" + myVar);
You can use javascript throw statement.
According to Mozilla MDN
Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.
Example:
throw "An error ocurred."
You can also go pro and throw an error object like this:
throw new MyAppError("custom error str", 128);

How to modify the locally defined variable in the it block when modifying it in the cascaded promises

I want to access/modify the locally defined variable of the it block inside the cascaded multiple promises
Something like this
describe('make the app to fail',function(){
it('should have error', function(){
var canYouModifyMe = 0;
anArrayofAlertElements.count().then(function(total){
anArrayofAlertElements.get(0).isDisplayed().then(function(value){
canYouModifyMe = 'yes'; // proven that it goes here
});
});
console.log(canYouModifyMe); // Here's the problem, this is still 0. Im expecting it to be "yes"
});
})
I already moved the variable in the onPrepare function (to make it globally accessible, but doesnt work)
How can i modify a locally defined variable in the it block in cascaded promise?
Just in case you want more detailed code, check the below code.
// html file
// different errors
<div class="alert alert-warning" ng-show="data.error" >
{{(data.message)}}
</div>
<div class="alert alert-warning" ng-show="cart.error" >
{{cart.message}}
</div>
...
- some other error goes here -
// page object
function Util() {
this.getAlertMessages = function(){
return element.all(by.css('.alert'));
}
this.expectAlertMessages = function(){
var that = this;
var errorCount = 0;
this.getAlertMessages().count().then(function(count){
for(i=0;i<count;i++){
that.getAlertMessages().get(i).isDisplayed().then(function(data){
// for debugging purposes, lets make it always true so it increments error count
data = true;
if (data===true) {
errorCount++; // here is the problem. it doesnt increment the above defined variable "errorCount"
}
});
}
return errorCount; // this is still 0
}).then(function(obj){
// errorCount still 0, that is supposedly 1
expect(errorCount).toBeGreaterThan(0);
});
}
}
In summary, i just want to test if there's any alert messages displayed.
Im stuck on this, hoping that someone here can help me.
The thing here is that we are talking about promises and async execution.
Definitely, by the time that you print the value of canYouModifyMe the callback from the promise in which you modify the value was not executed. Try below code to see that the execution order is different:
describe('make the app to fail',function(){
it('should have error', function(done){
var canYouModifyMe = 0;
anArrayofAlertElements.count().then(function(total){
anArrayofAlertElements.get(0).isDisplayed().then(function(value){
canYouModifyMe = 'yes'; // proven that it goes here
console.log('Inside callback. Current value is', canYouModifyMe);
done();
});
});
console.log('Current value is', canYouModifyMe); // Here's the problem, this is still 0. Im expecting it to be "yes"
});
})
Also, you should have noticed the usage of another done callback in above code. That is another detail about async execution and jasmine. Basically by running that callback, we tell the test (spec) That the execution for it has finished.

New to Javascript - Callback issue

I am new to Javascript programming coming from a Java and Objective C background. I am looking to learn a bit more about Javascript for hybrid mobile applications.
In doing so I am trying to do a login with a call back but I am having a little trouble understanding both the syntax and the way a callback works.
First up I am calling the following login function which just creates an ajax call to fetch some JSON at the minute for testing purposes:
testLogin.loginWithUsername ("test", loginCallback);
This works OK as I can see the 200 OK Status and the expected JSON in logging.
However the call back "loginCallBack" never gets called.
It is as follows:
loginCallback: {
success: function(id) {
alert ('success');
}
failure: function (id, error) {
alert ('failure');
}
}
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line. I can change it and the failure function to = function(id) and it the code runs then but the callback is never called.
I am using a library for the login that states the call back required is an object that needs a success and failure function and the code above is the given example.
So first off I don't understand why the above syntax works in the sample code but gives me an error when I run it?
Secondly am I calling the callback correctly? Both the loginWithUsername call and the loginCallback function are in the same Login.js file.
Here is an example how callback works:
First thing: you need to create a new object containing your functions/methods. Properties and methods are listed comma seperated.
// Creating new object with callback functions
var loginCallback = {
success: function(id) {
alert ('success');
} , // Add a comma
failure: function (id, error) {
alert ('failure');
}
}
function loginWithUsername(username, callback) {
if (username === 'test') {
var successId = 1;
callback.success(successId);
} else {
var errorId, errorMsg;
errorId = 0;
errorMsg = 'Error';
callback.failure(errorId, errorMsg);
}
}
Now you can call the function:
loginWithUsername('test', loginCallback);
And the result should be 'success'.
Edit:
But you can do this without an object, by passing the function directly:
// Creating function
function showMessage(message) {
alert(message);
}
function loginWithUsername(username, callback) {
if (username === 'test') {
callback('success');
} else {
callback('failure');
}
}
// Pass function
loginWithUsername('test', showMessage); // Result: 'success'
loginWithUsername('abcd', showMessage); // Result: 'failure'
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line.
Each property: value pair in an object literal must be separated with a comma.
}, /* Your comma is missing which is why you get a syntax error */
failure:
This:
loginCallback: {
is only acceptable if you want to define a property inside an object literal.
This:
testLogin.loginWithUsername ("test", loginCallback);
is using a variable.
You probably want:
var loginCallback = {
but it is hard to tell without more context.

Javascript Exit from child function

i have group of bind's, which gets trigger inside a function from before and after the code. like following:
function global() {
before(); // call all before binds here
//... mainFunction code...
after(); // call all after binds here
}
if one of functions inside before(); callback wants to exit or stop the global() from running further, how can i stop it, without checking the return values?
The only way to achieve this without checking the value returned, is to raise an exception by throwing an error.
function before() {
throw new Error('Ending execution');
}
function after() {
console.log('Have you met Ted?');
}
function global() {
before();
// never reaches here
after();
}
global(); // Error: Ending execution
console.log('foo'); // not executed
If you have global invoked somewhere and want any code following it's invocation to continue being executed, you'll need to wrap it with a try..catch, for example
function global() {
try {
before();
// never reaches here
after();
} catch (e) {
console.log(e); // log error. Leave this block empty for no action
}
}
global(); // Error logged
console.log('bar'); // still executed

Categories

Resources