I’m a newbie in programming language and I’m learning Javascript. I’m trying to understand the concept of callback function. I realized that callback is intended a function passed as parameter, but when does it call?
In the below examples I used a classic approach to write functions and then I tried to use the arrow function. The callback is done() function, in the first example it is called after the parent function, in the second one after.
What is the reason? Can you give me an explanation? Thank you so much for the feedback
Example no. 1
function done(){
console.log("Done");
}
function increment(num, callBack){
for(var i = 0; i <= num; i++){
console.log(i);
}
return callBack();
}
increment(10, done);
Example no. 2
const done = () => {
console.log("Done");
}
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
}
increment(10, done());
To use callback you need to specify that there'll be a callback function as a argument, and you need to call that somewhere in the parent function like this, and that's when it will be called:
function someFunction(callback){
//Do something if needed...
callback() //callback(someParameter) if you want to pass some parameter to the callback func
//Do something if needed...
}
In your 2nd example, it's actually not a proper way of using callback function because you did not call the callback function inside parent function. You can modify it to to make it work as 1st example like this:
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
done(); //call the callback function
}
increment(10, done); //just pass the name of callback func, not call it like you did "done()"
Related
I just come across the concept of decorator and apply-call methods.
Why should I use an apply method here, even if it works without that. I can just pass "return func(...args)" and it still works. I understood the concept if I was working with an object method while having a returning this I should have used "apply" or "call",but why is it forwarding the call here with a function? On top of that, how the ".calls" property is getting passed to work.calls ?
function work(a, b) {
alert( a + b );
}
function spy(func) {
function wrapper(...args) {
wrapper.calls.push(args);
return func.apply(this, args);
}
wrapper.calls = [];
return wrapper;
}
work = spy(work);
work(1, 2);
work(4, 5);
for (let args of work.calls) {
alert( 'call:' + args.join() );
}
In programming, there are multiple ways of doing the same problem. The following problem is in regards to palindrome. Though I feel that I am on the right track, I am not able to completely solve the problem to get to requested solution.
What is a palindrome? A word written forward or backward is the same and returns true. Example, "racecar". Hence, I designed the following code in Javascript...
function palindrome(string) {
string = string.toLowerCase();
lowString = string.toLowerCase().split("").reverse().join("");
for (var i=0; i<string.length; i++) {
if (string[i] !== lowString[i]) {
return false;
}
}
}
return true;
}
The above code returns true if Palindrome exists and returns false if not.
Then, the problem says - Given various palindrome in a string or array, please return the longest palindrome. So, I wrote the following:
function longestPalindrome(newstring) {
splitString = newString.split(" ");
for (var i=0; i < splitString; i++) {
if (splitString[i] == palindrome(splitString[i]) {
console.log(splitString[i]);
}
}
}
longestPalindrome("This is a racecar ada");'
But in the above code, I am not able to get the required outcome because I believe I am not calling the function correctly.
I would appreciate clear directions or even a solution built off of my track as well as the track you deem fittest.
I was wondering whether it's possible to wait for a callback before continuing a process.
I'm using a library that handles a future internally and then if it was successful, does a callback, otherwise handles the error internally with no callback.
Now I'm trying to use this library to create an instance, then fill it with random test data and then update that entity.
Map generateRandomizedInstance() {
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
return result2;
})
});
}
This would be fine if I'm only creating one entity and updating it once, but I want to create lots of random data:
ButtonElement b = querySelector("button.create")..onClick.listen((e){
for (int i = 0; i < 500; i++) {
generateRandomizedInstance();
}
});
It doesn't take long for this code to crash spectacularly as the callbacks aren't coming back fast enough.
I've tried changing the method signature to
generateRandomizedInstance() async {
and then doing:
for (int i = 0; i < 500; i++) {
print(await generateRandomizedInstance());
}
but that await syntax seems to be invalid and I'm not completely sure how to wrap that callback code in some kind of future that I can wait for the callback to come back before continuing to the next iteration of the loop.
I've tried a while loop at the end of generateRandomizedInstance that waits for a result variable to not be null, but that kills the browser and seeing as I'm not always getting a callback, in some cases it could cause an infinite loop.
Any ideas / suggestion on how to pause that for loop while waiting for the callback?
This should do what you want:
Future<Map> generateRandomizedInstance() {
Completer<Map> c = new Completer<Map>();
lib.createEntity((result1){
result1["a"] = generateRandomA();
result1["b"] = generateRandomB();
result1["c"] = generateRandomC();
...
lib.updateEntity(result1, (result2){
// want to return this result2
c.complete(result2);
})
});
return c.future;
}
ButtonElement b = querySelector("button.create")..onClick.listen((e) async {
for (int i = 0; i < 500; i++) {
await generateRandomizedInstance();
}
});
for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(function(browserLog) {
console.log(i);
});
}
I am trying to run this using protractor, but i get hundred times 100 printed in console. I have some functionality which am trying to implement using looping.How can i do looping in protractor?
This is because the functions you're passing to then all close over the variable i, not the value that variable has when you create the functions. So later, when the functions are called, they all see the value of i as it is then, after the loop is complete (100).
If you want to capture the value of i as it is when you create the function, you can use ES5's Function#bind:
for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(function(index, browserLog) {
console.log(index);
}.bind(null, i));
}
bind returns a new function that, when called, will call the original function with a given this value (in this case I'm using null) and any arguments you follow that with, followed by arguments given to the function bind returned.
Another approach is a builder function:
for ( i = 0; i < 100; i++) {
browser.manage().logs().get('browser').then(buildHandler(i));
}
function buildHandler(index) {
return function(browserLog) {
console.log(index);
};
}
That has the advantage of allowing the caller to control this.
I wrote a custom locator for Protractor that finds anchor elements by their ui-sref value. In my specs I just used by.addLocator to add the custom locator, but I figured this might be a cool thing to publish and have other people use it.
The goal is to add this custom locator to the global Protractor object so it can be used in any of your specs.
My initial approach was to add this functionality in the onPrepare block of the Protractor config. Something like the pseudocode below:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
That require statement would just execute this function:
function (ptorInstance) {
ptorInstance.by.addLocator('uiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};
The problem is that by is not defined on the protractor object available in the onPrepare block. This means that I cannot use the .addLocator method.
Try the following:
function () {
by.addLocator('uiSref', function (toState, opt_parentElement) {
...
By should be in the global scope.
The protractor object passed to the onPrepare block has a By property. That By property has an inherited enumerable property named addLocator. My understanding of JavaScript is pretty shallow so it really threw me off that when I console.log'ed the protractor.By it returned {}, but if I did for (var propName in protractor.By) it would show me all the "hidden" properties. I'm still struggling to understand that bit.
Working code:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
The require would execute the function below:
function (ptor) {
ptor.By.addLocator('linkUiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};