I am fairly new to NodeJS and to JavaScript in general. Here is my script:
var fs = require('fs') ;
var temp = "???";
var test = function (){
fs.readdir("./", function(err,result){
temp = result; // i change the temp's value
console.log("inter result ....."+temp); // temp's value changed
setTimeout(pr,1000,"inter setTimeout: "+temp); // temp's value changed
});
}
var pr = function (str){
console.log("Print str: "+ str);
} ;
test();
setTimeout(pr,1000,"Out setTimeout print: "+temp); // Why here temp's value not change???
How can I change to the var temp’s value outside the callback?
setTimeout(pr,1000,"Out setTimeout print: "+temp);
is the same as
var str = "Out setTimeout print: " + temp;
setTimeout(pr, 1000, str);
At this point of time temp still is "???". You have to use
setTimeout(function() {
pr("Out setTimeout print: "+temp);
}, 1000);
What order do the log statements appear in your console?
I'm not into node.js, but I would expect to see the "Out" one before the "inter" ones because I would guess the fs.readdir() function is asynchronous and that the callback function that you provide to it will not be executed until after you've already made the call to setTimeout() in the last line of your code at which point temp has not yet been changed.
That is, the sequence of execution I would expect from your code is:
define fs
define temp set to ???
define test function
define pr function
call test() function
within test() call the fs.readdir() but then return immediately from test() without the callback having been executed yet
setTimeout(pr,1000,"Out setTimeout print: "+temp); (where the value of temp at that moment - still "???" - becomes part of the string that setTimeout will pass to pr in one second's time)
the callback from fs.readdir() is executed, and only then does temp get changed. The "inter" timeout gets set.
Related
I am having trouble with the second function. It runs through before there is a value saved in 'w'. Ive tried setTimout() but it did not help. Im trying to implement async/await but im struggling with how it would fit with the code below:
function functionOne(){
var s
chrome.storage.local.get(['prm'], function(result) {
s = result.prm;
return s;
});
}
function functionTwo(){
let w = functionOne();
// second half runs after w is assigned a value (after functionOne is done running).
}
Is async/await the only solution or is there another way of solving it?
async / await is not the only solution. And in any case, you are going to need to create a promise in functionOne
/*async*/ function functionOne(){
var s;
var p = new Promise(function(success) {
chrome.storage.local.get(['prm'], function(result) {
s = result.prm;
success(s);
});
}
return p;
}
function functionTwo(){
let p = functionOne();
p.then(function(s) {
//...
});
}
You need to create a promise to be able to return the results of chrome.log.storage. You can make functionOne async or not. It doesn't change anything.
You would have to use an asynchronous function that does not work all at once.
You could do something like
function functionOne(){
var s
chrome.storage.local.get(['prm'], function(result) {
s = result.prm;
return s;
});
}
async function functionTwo(){
await let w = functionOne();
// second half runs after w is assigned a value (after functionOne is done running).
}
Referenced from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Note: I would also like to point out that functionOne actually returns an undefined value because inside the chrome.storage.local.get function the callback returns s, so you would need to move the return statement outside of the callback function.
I want a function that looks for elements with the "comment" class, and if the number of comments has changed, (if there is a new comment) it will call an other function. So this is what I did:
function main(num0){
var comments = document.getElementsByClassName("comment");
var num = comments.length;
if (num!=num0){
//function to call();
console.log("New Comment");
}
setTimeout(main(num),10); //check every 10 for new comments
}
main(0);
num0 is the number of comments the last time the function was called so I try to recall the same function but num0 takes the value of num, but it doesn't seems to work.
I recommend using setInterval. calling recursion at higher rate may cause different errors after some time.
let num = 0;
setInterval(()=>{
var comments = document.getElementsByClassName("comment");
var num1 = comments.length;
if (num!=num1){
//function to call();
console.log("New Comment");
num=num1
}
},10)
Your use of setTimeout is invalid; you are calling the function main instead of providing setTimeout with a callback. I also believe you need to pass num0 instead of num in your timeout.
Try this:
function main(num0){
var comments = document.getElementsByClassName("comment");
var num = comments.length;
if (num!=num0){
//function to call();
console.log("New Comment");
}
setTimeout(main, 10, num0); // Changed this line
}
main(0);
Review this regarding the setTimeout function:
https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout takes a function reference. In your case you aren't passing the reference, you are passing the result of that function by calling it.
Example of syntax that does what you intend it to do:
setTimeout(() => main(num),10); //check every 10 for new comments
https://www.w3schools.com/jsref/met_win_settimeout.asp
Kyle Simpson has an amazing class on pluralsight.
In one of the modules, he goes through a snippet of code that can be safely called asynchronously, and be certain that the results are going to be shown to the user in the same sequence with which the code was executed.
The function in its glory:
function getFile(file) {
var text, fn;
fakeAjax(file, function(response){
if (fn) fn(response);
else text = response;
});
return function(cb) {
if (text) cb(text);
else fn = cb;
}
}
We can call it like so:
I'm having a tough time understanding the getFile function:
where is cb defined? how does it get called, i.e. cb(text) if it's not defined anywhere?
when we call getFile, how does the response get a value at all?
getFile returns an anonymous function:
return function(cb) {
if (text) cb(text);
else fn = cb;
}
so var th1 = getFile("file") ends up assigning that anonymous function to the value of th1, so th1 can now be called with an argument - which becomes cb. So when later, we call th1 with:
th1(function(text1) {
...
we are passing in a second anonymous function (with argument text1) which is assigned to cb (shorthand for 'callback').
The reason it works is that when the ajax is complete, it does one of two things:
if fn is defined, calls fn with the response
if not, it stores the response
Conversely, when the returned anonymous function is called, it does one of two things:
if text is defined (i.e. a result is already received) then it calls the callback with the response
if not, it assigns the callback (cb) to fn
This way, whichever happens first - ajax complete, or thunk called, the state is preserved, and then whichever happens second, the outcome is executed.
In this way, the 'thunks' can be chained to ensure that while the ajax functions happen in parallel the output methods are only called in the sequence in which the fn values are assigned.
I think part of the confusion is unclear variable naming, and the use of liberal anonymous functions with out giving them an intention revealing name. The following should be functionally equivalent with clearer naming (I think):
function getFile(file) {
var _response, _callback;
fakeAjax(file, function(response){
if (_callback) _callback(response);
else _response = response;
});
var onComplete = function(callback) {
if (_response) callback(_response);
else _callback = callback;
}
return onComplete;
}
then:
var onFile1Complete = getFile("file1");
var onFile2Complete = getFile("file2");
var onFile3Complete = getFile("file3");
var file3Completed = function(file3Response) {
output("file3Response");
output("Complete!");
}
var file2Completed = function(file2Response) {
output(file2Response);
onfile3Complete(file3Completed)
}
var file1Completed = function(file1Response) {
output(file1Response);
onFile2Complete(file2Completed);
}
onFile1Complete(file1Completed);
Can I call a timeout function on the returned element in this if statement?
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').html(data);
}
I've tried the following:
if(data){
setTimeout(function() {
return jQuery('<div class="thisDiv"></div>').html(data);
}, 100);
}
But I get this error in my console:
Uncaught TypeError: Cannot read property 'nodeType' of undefined
The return statement will return from the anonymous function you passed into the setTimeout function, not the function enclosing the scope of the if statement. Try passing a callback into the function containing the if statement, then calling that callback with the data as a parameter.
function delayedReturn(callback) {
if(data) {
setTimeout(function() {
callback(jQuery('<div class="thisDiv"></div>').html(data));
}, 100);
}
}
No. You cannot use setTimeout to delay when a function will return. It is not a sleep function. It puts a function on a queue to run later, it doesn't stop all processing for a period of time.
function a() {
return 1;
}
var x = a();
In the above you have a single function which has a return statement. The value it returns is assigned to x.
function b() {
setTimeout(function c() {
return 1;
}, 1000);
}
var y = b();
Now you have two functions. b has no return statement, so it returns undefined and undefined is stored in y.
b uses setTimeout to call c, and c has a return statement. setTimeout doesn't do anything with return values though, so the return value of c is discarded.
Any time you are dealing with asynchronous functions, you have to do something with the data inside the asynchronous callback (such as call another function and pass the data as an argument). There is no going back, it is too late for that.
You could return a Promise from b though. That would allow other code to use the value of y to bind event handlers that will fire when the timeout expires.
You certainly can, you'd need to remove the return and use a valid selector to target your div.
Something like this would work:
HTML
<div class="thisDiv">test</div>
Javascript:
var data = 'some stuff';
if(data){
setTimeout(function() {
jQuery('.thisDiv').html(data);
}, 100);
}
You can see it working here: https://jsfiddle.net/ckkz1wbf/
Question, Why are you using:
jQuery('<div class="thisDiv"></div>')
Are you try to create an element, if that the case, you could use delay from jquery.
function fn(){
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').delay(100).html(data);
}
}
In the below code, I want to know what would be the value of tabId inside doStuffWithReport function. Would it be the same value of tabId that was sent while calling sendMessage or it might change during the course of period?
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// we suppose that tabId is 5.
function doStuffWithReport(report) {
// what would be the value of tabId? still 5? or it might change to
// something else if, in the meantime, we received another
// call for chrome.tabs.onUpdated?
}
// we are sending a message to tabId 5.
chrome.tabs.sendMessage(tabId, {
text: 'report_me'
}, doStuffWithReport);
});
Edit: I tested it myself. It remains the same, i.e., tabId would remain 5 even if there is another call on chrome.tab.onUpdated.
Well, first let's simplify the code to look at the underlying behavior:
function outside(){
var out = 5;
function inside(){
console.log(out);
}
inside();
}
In this example it will obviously print out 5 when outside is called, but since inside is only defined locally, it will be undefined unless called from within outside.
To make it a bit more complex, let's not make out static and have it based on a parameter:
function outside(out){
function inside(){
console.log(out);
}
inside();
}
Now it is pretty much the same as before and will print out whatever we use as a parameter right away. Let's make it a bit more async by having inside be called after a random amount of time of up to a second and compare the then current value of out with the value of out that is printed at the time inside is called while calling it several times consecutively.
function outside(out){
function inside(){
var dt = Date.now();
console.log(dt + ' : ' +out);
}
var n = Math.floor(Math.random() * 1000);
var d = Date.now()+n;
console.log(d + ' : ' + out);
setTimeout(inside,n);
}
for(var x=0;x<25;x++){outside(x);}
From the output of this, we can see that the value of out that inside has at the time of being called is the same value as when we set the timeout for inside to be called.
From this we can say that tabId would indeed still be 5 when doStuffWithReport is called.