test = function(x){
if ( some conditions ) { return true; }
else { return false; }
}
if (test(y)) {document.write("You have done this before!")};
console.log("Checked!");
The intention is to check if the user performed some action in the past. These are just mock up codes that do not really reflect what I am actually doing though.
Question:
I am relatively new to node.js so please forgive me if this sounds trivial. Suppose test(y) is true. Can I be sure that the console.log will be executed after the document.write? Even if test(y) takes a long time to run?
In other words, I need "if (test(y))..." to be blocking. I understand that passing a function as an argument, e.g. setInterval(test(y),100); can be async and non-blocking. But what about "if(test(y))..."?
NodeJS has both synchronous (blocking) and asynchronous (non-blocking) functions. (More accurately: The functions themselves are always "blocking" but a whole class of them start something that will complete later and then return immediately, not waiting for the thing to finish. Those are what I mean by "non-blocking.")
The default in most cases is asynchronous (and they accept a callback they call when the thing they've started is done); the synchronous ones tend to have names ending in Sync.
So for example, exists is asynchronous (non-blocking), it doesn't have a return value and instead calls a callback when it's done. existsSync is synchronous (blocking); it returns its result rather than having a callback.
If test is your own function, and it only calls synchronous functions, then it's synchronous:
function test(x) { // Obviously a nonsense example, as it just replicates `existsSync`
if (existsSync(x)) {
// The file exists
return true;
}
return false;
}
// This works
if (test("foo.txt")) {
// ...
}
If it calls an asynchronous function, it's asynchronous, and so it can't return a result via a return value that can be tested by if:
// WRONG, always returns `undefined`
function test(x) {
var retVal;
exists(x, function(flag) {
retVal = flag;
});
return retVal;
}
Instead, you have to provide a callback:
function test(x, callback) {
exists(x, function(flag) {
callback(flag);
});
}
// This works
test("foo.txt", function(flag) {
if (flag) {
// ...
}
});
Yes, this code is synchronous executed and "blocking". But console.log will be executed every time the script runs because you only omitting the document.write in the if statement.
The blocking/non-blocking terminology is a bit confusing here, I would say 'all functions in Node.JS are blocking and all IO in node standard library is non-blocking, except when indicated explicitly by Sync suffix in function name'.
Related
I was unsure how node.js was able to realize what functions where async and which were not and how to create a custom async function.
Say I wanted to create a custom asynchronous function. I would be surprised if just because I called my last argument to the async function callback or cb that it would just know its an async function:
function f(arg1, callback){
//do stuff with arg1
arg1.doStuff()
//call callback
callback(null, arg1.result());
}
I tried something like that and it did not work async. How do you tell node.js that f is actually async?
NOTE: this answer was written in 2014, before the existence of async function, and before Promises gaining popularity. While the same principles apply as well, I would recommend reading on Promises before trying to get your head around how they relate to "traditional" callback-driven async functions.
To create a function that calls its callback asynchronously, you have to use some platform-provided async primitive (typically IO-related) on it - timers, reading from the filesystem, making a request etc.
For example, this function takes a callback argument, and calls it 100ms after:
function asyncFn(callback) {
setTimeout(() => {
callback();
}, 100);
}
A possible reason for making a function async when it doesn't need to be, is for API consistency. For example, suppose you have a function that makes a network request, and caches the result for later calls:
var cache = null;
function makeRequest(callback) {
if (!cache) {
makeAjax(result => {
cache = result;
callback(result);
});
} else {
callback(cache);
}
}
The problem is, this function is inconsistent: sometimes it is asynchronous, sometimes it isn't. Suppose you have a consumer like this:
makeRequest(result => doSomethingWithResult(result));
doSomethingElse();
The doSomethingElse function may run before or after the doSomethingWithResult function, depending on whether the result was cached or not. Now, if you use an async primitive on the makeRequest function, such as process.nextTick:
var cache = null;
function makeRequest(callback) {
if(!cache) {
makeAjax(result => {
cache = result;
callback(result);
});
} else {
process.nextTick(() => callback(cache));
}
}
The call is always async, and doSomethingElse always runs before doSomethingWithResult.
Only native functions (with access to the event loop) are asynchronous. You would need to call one of them to get asynchronity for your callback. See What is a simple example of an asynchronous javascript function?.
If you aren't using any, there's hardly a reason to make your function asynchronous.
I am working on this function on Node.js, with the following requirements:
As far as possible, maintain synchronous code flow (so that it is simple to read/follow)
Able to return value, so that it can be passed up to the higher-level function.
If asynchronous function has to be used, there has to be some way to "block" the flow between the asynchronous function and return statement, while at the same time not blocking the program and GUI.
Here is my code:
main.js
var some = require("./some.js");
main_fn = function () {
var result = some.some_fn();
if (result == "good") // do something
};
main_fn();
some.js
exports.some_fn = function () {
var result;
var someInterval = setInterval(function () {
// output to GUI
if (condition1) {
clearInterval(someInterval);
result = "good";
} else if (condition2) {
clearInterval(someInterval);
result = "bad";
}
// else continue with interval
}, 250);
// previous way: deasync
// it will not block event loop, however it will block the GUI ("freeze" the browser)
// require("deasync").loopWhile(function () { return result === undefined; });
// result will be undefined here if no code to "block" in between
// but I need result to be either "good" or "bad"
return result;
};
As you can see from the code, I had tried deasync (https://github.com/abbr/deasync). However, that will block the GUI. Are there any Node.js modules/workaround, something like deasync, that allow me to maintain this code structure (as far as possible) and meet my requirements on top?
It will be even better to find a solution without using native Node.js modules (modules which use C/C++ code, like deasync), as I may need to browserify the program in the future. However, I am fine with hearing any solutions from you. Thanks!
It is fundamentally impossible to "deasync" without blocking.
"Asynchronous" means that the result will be produced at some later time. "Synchronous" means that code execution will continue right now. These two simply do not go together. If a synchronous operation needs to wait for the completion of an asynchronous operation, it must suspend operation until the operation has completed; that means it'll block.
The friendliest syntax without devolving into callback hell is to use Promises. They sort of allow you to write synchronous-ish looking code while delegating the intricacies of asynchronous callbacks into the background.
I am new to nodejs, recently I am not sure how to arrange tasks in order such that they behave correctly.
below are two examples
arr.forEach(function(elem){
//do many many things
});
console.log('done, now take ur pick');
stdin.on('input', function action(){
...
})
how can I set stdin.on fire after arr.forEach.
and question 2 I think if I do
fn1();
fn2();
function fn1(){
//long long code
}
function fn2(){
console.log('fn2 is done!')
}
and runs the above, the execution will be in a thread of
fn1 fn2 fn1 fn1 fn1, right? how to prevent this?
Functions in node.js are either synchronous or asynchronous. Synchronous code runs in a single thread, and behaves exactly like the code you're used to:
fn1();
fn2();
fn3(fn4());
Will run fn1, then fn2, then fn4, then fn3 (passing in the result of fn4 as a parameter).
Asynchronous code fires off some action, and takes as a parameter the function to execute when it's done (which might, in turn, fire off another asynchronous action). You get control back immediately. Example:
doSomeAsyncThing(function () {
console.log("did the async thing");
});
console.log("hello");
executes like this: First, the asynchronous action is fired off, then "hello" is printed. Some time later, the asynchronous action completes, so the callback is called, and "did the async thing" is printed.
If you want to do one asynchronous thing, then do another asynchronous thing after the first one is finished, the standard way to is nest the callbacks:
async1(function() {
async2(function() {
console.log("async1 and async2 finished");
});
});
Although there are better options.
So in your second example, if fn1 is synchronous, it will work perfectly exactly as you wrote it. If fn1 has to do something asynchronous, it too will have to be asynchronous, so you will have to write it like this:
function fn1(callback) {
// do some sync stuff
doSomethingAsync(function () {
// do more sync stuff
doSomethingMoreAsync(function () {
// do more sync stuff
callback(); // call the callback once everything is completed
});
});
}
And then call it like this
fn1(function () {
fn2();
});
Which could be simplified to:
fn1(fn2);
In your first example, note that array.forEach is synchronous. If your // do many many things are all synchronous, then that will work exactly as you wrote it, but if there's an asynchronous action in there, you can either manually implement a counter, or just use the async library or Promise iterator utilities.
by adding the stdin to the callback function of the forEach function. Like:
arr.forEach(function(elem){
//do many many things
}, function() {
console.log('done, now take ur pick');
stdin.on('input', function action(){
...
});
});
Using this, the stdin and console.log functions will be called only after completion of the forEach loop.
I'm building a Chrome extension and I wrote this code.
var Options = function(){};
Options.prototype = {
getMode: function(){
return chrome.storage.sync.get("value", function(e){
console.log(e); // it prints 'Object {value: "test"}'.
return e;
});
},
setMode: function(){
chrome.storage.sync.set({"value": "test"}, function(e) {
})
}
}
var options = new Options();
options.setMode();
console.log(options.getMode()); // it prints 'undefined'.
I expected it to print
Object {value: "set up"}
when I call options.getMode(), but it prints undefined.
Does anyone know how to fix this problem?
The chrome.storage API is asynchronous - it doesn't return it directly, rather passing it as an argument to the callback function. The function call itself always returns undefined.
This is often used to allow other methods to run without having to wait until something responds or completes - an example of this is setTimeout (only difference is that it returns a timer value, not undefined).
For example, take this:
setTimeout(function () { alert(1); }, 10000);
alert(0);
Because setTimeout is asynchronous, it will not stop all code until the entire function completes, rather returning initially, only calling a function when it is completed later on - this is why 0 comes up before 1.
For this reason, you cannot simply do something like:
// "foo" will always be undefined
var foo = asyncBar(function (e) { return e; });
Generally, you should put what you want to do in your callback (the function that is called when the asynchronous function is completed). This is a fairly common way of writing asynchronous code:
function getValue(callback) {
chrome.storage.sync.get("value", callback);
}
You could place an entire portion of your code inside the callback - there's nothing stopping you from doing so. So instead of doing the following:
console.log(getValue()); // typical synchronous method of doing something
This would probably be a better idea:
// how it would be done in asynchronous code
getValue(function (value) {
console.log(value);
});
Chrome storage API is asynchronous and it uses callback, that's why you're getting this behavior.
You can use Promise API to overcome this asynchronous issue, which is simpler and cleaner. Here is an example:
async function getLocalStorageValue(key) {
return new Promise((resolve, reject) => {
try {
chrome.storage.sync.get(key, function (value) {
resolve(value);
})
}
catch (ex) {
reject(ex);
}
});
}
const result = await getLocalStorageValue("my-key");
The chrome.storage.sync.get is called asynchronously, that's why you have to pass it a callback, so that it is executed in the future.
When you try to print the returned value of getModeyou are printing the return value of whatever chrome.storage.sync.get returns after queuing the asynchronous call to be executed.
This is a common mistake people do in javascript, while they are learning to use asynch calls.
In node.js, is it possible to determine (using a function) whether a method is synchronous or asynchronous?
I'd like to write a function that does the following:
function isSynchonous(methodName) {
//if the method is synchronous, return true. Otherwise, return false.
}
From a language standpoint this is not possible, which I believe llambda's answer proves.
Functions can do things asynchronously but return something synchronously; say, return the number of async tasks that were fired off.
Functions can synchronously return promises... that represent asynchronous information. I would call such a method asynchronous but the language can't really tell that.
In some perverse sense every asynchronous function "returns" something... undefined if nothing else.
From an engineering standpoint:
read the documentation.
If the function accepts a callback, it is likely asynchronous. Look at the function signature.
Read the code.
Use "common sense." If the function does IO and returns a result from IO it must be, in some case, asynchronous. This includes file reading, reading from standard input, saving to a database, and HTTP/AJAX requests. Note streams are often used for this, which represents an asynchronous task, but the callbacks are special.
Furthermore there are functions that mix the two.
function(callback) {
if(ready) {
callback();
}
else {
setTimeout(callback, 5000);
}
}
Arguably this is very evil, and correct practice would be
if(ready) {
process.nextTick(callback);
}
so the function has uniform behavior.
However there is a hacky way to tell if anything asynchronous happened, at least in Node.js. See this discussion.
// untested!! please read the documentation on these functions before using yourself
var work = process._getActiveHandles().length + process._getActiveCallbacks().length;
foo;
var newWork = (process._getActiveHandles().length + process._getActiveCallbacks().length) - work;
if(newWork > 0) {
console.log("asynchronous work took place.");
}
This works because asynchronous work cannot resolve on the same tick, by definition, and because Node.js is single threaded.
You don't necessarily know. A function could even be randomly synchronous or asynchronous.
For example, a function that takes another function could execute that function immediately, or it could schedule to execute it at a later time using setImmediate or nextTick. The function could even randomly choose to call its passed function synchronously or asynchronous, such as:
console.log('Start')
function maybeSynchOrAsync(fun) {
var rand = Math.floor((Math.random() * 2))
if (rand == 0) {
console.log('Executing passed function synchronously')
fun()
console.log('Done.')
} else {
console.log('Executing passed function asynchronously via setImmediate')
setImmediate(fun)
console.log('Done.')
}
}
maybeSynchOrAsync(function () { console.log('The passed function has executed.') });
Further, technically speaking, every function call is synchronous. If you call a function F, and F queues a callback function to be invoked later (using setTimeout or whatever mechanism), the original function F still has a synchronous return value (whether it's undefined, a promise, a thunk, or whatever).
No, that's impossible. The methods aren't just marked synchronous or asynchronous, they either use callbacks or they don't.
Why exactly do you need to know, is the real question.
Having said that; that's possible with the new JS abstractions. Nowadays for the async functions those explicitly defined by a preceding async keyword you can perform a test like;
async function test(){}
var type = Object.getPrototypeOf(test).constructor.name;
console.log(type); // <- 'AsyncFunction'
cool..!
As for the normal functions those happen to return a promise, we must remember that it's just a sync function returning a promise object right away, synchronously. That means you have to check dynamically if a function returns a promise in advance, before invoking the function. I think that takes you to a type level programming adventure which exists in sophisticated languages like Haskell etc.