How do you create custom asynchronous functions in node.js? - javascript

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.

Related

Why do we need callback instead of calling directly inside the function? in JS

I just realized that I do not understand javascript enough, despite the fact that I have been coding it for some time.
What I am not comfortable is Javascript Async.
until now I have been using callback and promise, because documentations and tutorials did it so as below.
$.get("some/url", function() {
// callback body
})
axios.get('some/url').then(res => {
console.log(res.data);
});
arr.map(element => console.log(element))
I know callback is used to my our code asynchronous
function doSomething(cb) {
console.log("this function receives callback function");
cb();
}
but what if we just call the function inside the function manually
function func1() {
// function body
}
function doSomething() {
console.log("this function receives callback function");
func1();
}
What I thought is as long as function is called at the right time, we do not have to use callback.
or is it because callback does its work while some other operations are going on?
If so, doesnt it break the principle of javascript as single threaded?
because its doing two things at the same time.
besides, do people use promise over callback function because of its readability and you could use Promise.all() ?
I feel like I am missing a core advantage of using promise.
Kindly please help me understand better.
If you don't use a callback, then you can only call func1(). The original doSomething() is more general, since you can call different functions depending on what the caller needs.
function func1() {
// function body
}
function func2() {
// function body
}
doSomething(func1);
doSomething(func2);
Is exactly the difference between hard coding data in your code or getting it dynamically.
In backend for example you make the code so it can serve different users different needs... at the same time, the same code...
So in this example:
function doSomething(cb) {
console.log("this function receives callback function");
cb();
}
you can build a functions that serve different users different information depending on the cb it receives...
in this example:
function func1() {
// function body
}
function doSomething() {
console.log("this function receives callback function");
func1();
}
it just runs a specific function func1 and that's it
It is all about reusability. If you call pass your callback into the utility function, in your example it is doSomething, you will not be able to reuse doSomething function in other parts of your program. You have just created a tight coupling between two functions.
If you program to the interface, and define which kind of callback you are expecting in your doSomething function, you will be able to use this doSomething function anywhere. It will not have to know which exact function to call, it will just concern about having a callback which expects n parameters in some order which.

How can you use a callback to guarantee sequential execution?

I am trying to wrap my head around callbacks and I do not understand how callbacks guarantee that a statement will execute after(in terms of time) another statement which takes an unknown amount of time. I do not care about promises,await,async, etc but just plain callbacks as I am trying to learn.
For example below, my method will execute the callback before the unknown time event has occured. I can see how callbacks can be used to execute something because an event occurred but not how they can be used to guarantee that something will be executed after(in terms of time) something else has finished executing and returned something meaningful.
function foo(callback) {
setTimeout(() => console.log("Do something with unknown time"),
2000);
callback();
}
function callback() {
console.log("Execute callback");
}
foo(callback);
So what I am asking is can callbacks be used to guarantee execution sequence in the time domain ? Or is their only purpose responding to events ?
Callbacks is a way of invoking a function that is passed as a parameter to invoker function(in your example foo). Callbacks guarantee that a function will be invoked if no error occurs before it's call inside the function. Callbacks aren't asynchronous either but the way it executes later inside the function after some line of code makes everyone think it as asynchonous at first.
And as you've added setTimeout function on the above example, setTimeout is an asynchronous callback envoker function that calls it's callback(in your code () => console.log("Do something with unknown time")) asynchronously after a certain defined time(2000). So, setTimeout wont stop the execution for 2 seconds as you've expected, instead it let's the further line of codes execute without worrying about what will happen inside it's callback. So, the callback() will trigger at that instant when foo(callback); is triggered.
You can find more info about callback in here.
You have asked two questions,
Is callback execution sequence guaranteed?
Is callback only respond to events ?
Answer
Yes.
From my understanding, callback is just calling another function to be run now (when it is called)
It is guarantee to run immediately when you call it.
To ensure something is called before the callback is triggered, simply put the things you want to call execute first before callback is conducted.
e.g. from your code, by modify it a bit, callback is guarantee to run after the console.log is executed.
function foo(callback) {
setTimeout(() => {
console.log("Do something with unknown time");
callback();
}, 2000);
}
function callback() {
console.log("Execute callback");
}
foo(callback);
It is the setTimeout which defers the execution, and is not related to callback methodology.
Sure, callback can be used as a callback to respond to event, just like elem.addEventListener("click", callback);. But not only that.
A simple example will be illustrated below.
e.g.
var map = function(arr, callback) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
result.push(callback(arr[i]));
}
return result;
};
map([0, 1, 2, 3], function(item) {
return item * 2;
})
Edited
This edit is referring to
For example, if I am making a database call, I do not know how much time it is going to take for the data to be retrieved. If i try to access it before it has arrived, I'll get an error.
Calling a database, is by no means different from an async http request. So here, I will use XMLHttpRequest to demonstrate how to use callback to ensure this. But normally, these are features provided in browser or node.js already. So you do not need to write it by your own. Of course, to prevent callback hell, I will personally prefer use of Promise or async/await. But this is a bit out of topic.
So let see how XMLHttpRequest can use callback to handle async task.
var sendRequest = function(callback) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this);
}
};
xhttp.open("GET", "filename", true);
xhttp.send();
}
and you can use callback to handle async event. Sometime you dont know when it will happen. And the basic idea how it works is from the example I have said in answer 1.
If I understand you mean correctly, you can use callback as an event to do something, such as: onerror, oncomplete...
In this example, we start to run todo function, and we have oncomplete function which can be used as callback to do something after completing works on todo function.
While running, if there is some error, it will be logged to onerror function.
function todo(oncomplete, onerror) {
try {
console.log("Start...");
console.log("Do something with unknown time");
setTimeout(() => oncomplete(),2000);
// you can try to throw error here to test
// throw new Error("Some error message...");
} catch (e) {
onerror(e);
}
}
function oncomplete() {
console.log("Done!");
}
function onerror(e) {
console.error(e.message);
}
todo(oncomplete, onerror);

Wait for async task to finish

I'm interacting with a third-party JavaScript library where some function calls are asynchronous. Instead of working the asynchronous logic into my application, I preferred to write synchronous wrappers to those async calls. I know, I know, it's terrible design, but this is a demo project with very high chance of being rewritten entirely. I need something to show the team the concept, not really having to worry performance, yet.
Here's what I wanna do:
function sync_call(input) {
var value;
// Assume the async call always succeed
async_call(input, function(result) {value = result;} );
return value;
}
I tried the jQuery's deferred and promise but it seems to be aiming at the async design pattern. I want to use the synchronous pattern in my code.
This will never work, because the JS VM has moved on from that async_call and returned the value, which you haven't set yet.
Don't try to fight what is natural and built-in the language behaviour. You should use a callback technique or a promise.
function f(input, callback) {
var value;
// Assume the async call always succeed
async_call(input, function(result) { callback(result) };
}
The other option is to use a promise, have a look at Q. This way you return a promise, and then you attach a then listener to it, which is basically the same as a callback. When the promise resolves, the then will trigger.
How about calling a function from within your callback instead of returning a value in sync_call()?
function sync_call(input) {
var value;
// Assume the async call always succeed
async_call(input, function(result) {
value = result;
use_value(value);
} );
}
Here is a working example of how:-
function testAsync(){
return new Promise((resolve,reject)=>{
//here our function should be implemented
setTimeout(()=>{
console.log("Hello from inside the testAsync function");
resolve();
;} , 5000
);
});
}
async function callerFun(){
console.log("Caller");
await testAsync();
console.log("After waiting");
}
callerFun();
Outputs:
Caller
Hello from inside the testAsync function
After waiting
To make it more complete, error handling should be added (deal with the reject() case).
See here for other examples: https://www.delftstack.com/howto/javascript/javascript-wait-for-function-to-finish/

Is there a pattern to manage javascript sync and async call

I have a javascript app saving all data on server, then use REST API communicate server and client.
They works fine, until we start have more and more nested async call or nested sync call which hiding async call. For example:
function asyncFoo(callback) {
callback();
}
function syncCallHidingAsyncCall(){
syncStuff();
asyncFoo(function(){
syncFoo()
});
}
function nestedAsyncCall(callback){
asyncFoo(function(){
anotherAsyncCall(callback);
})
}
// this make refactor code become so hard.
// if we want add step2() after nestedAsyncCall();
// instead of add one line of code
// we need first add callback param in every asyncCall, then pass step2 as a callback
And some unnecessary async call:
// we actually only verify this once.
function isLogin(callback){
if (!App._user) {
ServerApi.getCurUser(function(data){
App._user = data.user;
callback(App._user)
});
}
callback(App._user)
}
function syncCallNeedVerfifyLogin(callback){
// user only need login once, so in most case this is really only a sync call.
// but now I have to involve a unnecessary callback to get the return value
isLogin(function(){
callback(syncStuff())
})
}
So after the project become bigger and bigger, we start forgot their relationship, which one need wait, which one will do magic. And more and more function become async only because some very small thing need be verify on server.
So I start feel their must be some design problem in this project. I am looking for the best practice or design patter, or some rules need follow in this kind heavy communicate app.
Thanks for help.
They exist in several patterns to manage asynchronous data exchange and routine execution. They are called in different names as well:
Promises
EventEmitters
Deferred Objects/Deferreds
Control Flow Libraries
Futures
Callback aggregators
Observer / Publisher-Subscriber
A common implementation is jQuery's Deferred Objects which is also used in managing it's AJAX methods. In NodeJS, there is also AsyncJS and the native EventEmitter. There's even a 20-liner library made by some guy that implements EventEmitter which you could use.
As Bergi says in the comments, the pattern you're looking for is called deferred / promises. There's an implementation built into jQuery. From the docs:
a chainable utility object created by calling the jQuery.Deferred()
method. It can register multiple callbacks into callback queues,
invoke callback queues, and relay the success or failure state of any
synchronous or asynchronous function.
There are a variety of other implementations some of which are outlined in this stackoverflow question.
Make yourself a queue system, something like:
function Queue() {
this.queue = [];
}
Queue.prototype.i = -1;
Queue.prototype.add = function(fn) {
if (typeof fn !== "function")
throw new TypeError("Invalid argument");
this.queue.push(fn);
}
Queue.prototype.next = function() {
this.i++;
if (this.i < this.queue.length) {
this.queue[this.i].appy(this, arguments);
}
}
Queue.prototype.start = function() {
if (this.i !== -1)
throw new Error("Already running")
this.next.apply(this, arguments);
}
And use it like this:
var q = new Queue();
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.start();
DEMO: http://jsfiddle.net/4n3kH/

Why does this async.js series not behave synchronously

I'm attempting to use async.js to manage callbacks in an application. Below is an example of that code. However, I've run into a problem where the series of functions continues executing before one of the prior functions completes. For example, the resizeImage() function is still working when saveImageData() fires. But my intention is for the image to be saved only after it is resized. Shouldn't async.js handle this? If I have to pass a callback to resizeImage() what is the value of using async.js? Can someone show how using an async library is helpful in the example that I've given?
if (req.files) {
//removed some code not relevant to the question
async.series([
function (callback) {
model.saveImageData(tempPath, originalImage, s3Headers);
callback(null);
},
function (callback) {
var src = tempPath;
dst = path.dirname(tempPath) + "\\" + newImage;
model.resizeImage(src, dst);
callback(null);
},
function (callback) {
//the next function gets called before resizeImage() finishes executing
model.saveImageData(dst, newImage, s3Headers);
callback(null);
}
]);
}
Most likely saveImageData and resizeImage are non-blocking, asynchronous calls. Given they're doing I/O.
So you call resizeImage, it starts processing, returns control while it waits for IO, and your code immediately invokes the async.js callback that indicates that the function has finished it's work.
Instead, you should only call the async callback parameter after saveImageData and resizeImage complete, which means creating and using a callback function:
// this is just a guess at the api.
async.series[function(callback) {
model.resizeImage(src,dst,function() {
callback(null);
});
}];
You still have to ensure that the code inside each async function invokes the callback at the appropriate time.

Categories

Resources