In this question, I just want to confirm that we cannot use callback to strictly handle asynchronous tasks in JavaScript.
For example, we use Promise.then or async/await:
myPromise().then(callback);
// or
(async () => {
const res = await myAsyncFunction();
callback(res);
})()
I saw many examples with callback but they used setTimeout:
const functionWithCallback = (asyncFunction, callback) => {
asyncFunction();
setTimeout(() => {
callback();
}, 1000);
};
The example above is NOT asynchronous handling to me because we don't know the time asyncFunction() complete. 1000ms here is just a number.
Do we have any way to handle it with callback only?
The example above is NOT asynchronous handling to me
You are right that the timing of the callback invocation does not depend on whether myAsyncFunction completed its asynchronous task or not. However, in the most common use of the terminology, setTimeout is calling its callback function asynchronously... always.
I just want to confirm that we cannot use callback to strictly handle asynchronous tasks in JavaScript.
You can. But there are several things to note:
Even promises work with a callback system: the then method takes a callback argument, and that callback will be executed when the promise is fulfilled. Promises do not abolish callbacks, but make it easier to work with them by allowing to chain and to avoid "callback hell".
Before promises were available in JavaScript, there surely was already the concept of asynchronous programming.
In your examples you provided a function myAsyncFunction. If it is important to react when its asynchronous tasks have completed, then surely that function must somehow notify of that completion.
Today it is very common for such an asynchronous function to return a promise, and then the caller will of course make use of that promise (with either then or await): that's the purpose of having the promise object. A known example of such an asynchronous function is fetch.
If myAsyncFunction does not return a promise, then we would expect such a function to notify in a different way. For instance, it could take a callback as argument. Then to code looks like this:
myAsyncFunction(callback);
Known examples of such asynchronous functions are setTimeout, requestAnimationFrame, and queueMicrotask
Still other asynchronous functions are more complex, as they may provide some synchronous results and other asynchronous results. They return an object to which a listener can be attached. The code will then look something like this:
let res = myAsyncFunction();
res.addEventListener("ready", callback);
There are many examples of this in the DOM API: for instance, document.createElement and the load event (typically used with img and script elements).
A slight variation of this, is where a constructor is called with new, or where the object is provided first, but the asynchronous action still has to be initiated by some event, or by a method call.
There are of course many variations to this, like:
let res = new MyConstructor();
res.myAsyncFunction();
res.onready = callback;
An example of such a constructor is XMLHttpRequest (with its send() method)
Conclusion
It really depends on how myAsyncFunction will notify that it has completed its asynchronous tasks. When myAsyncFunction returns a promise, then of course you should be using that promise. When not, there should be some way to provide your callback to the API that is offered.
Related
I have a doubt the JavaScript Is a single-threaded synchronous programming Language. and it has only One Callstack .then How the Callback and promise Achieve Asycrones property?
They don't. Callbacks and Promises do not make anything asynchronous. Instead callbacks and Promises are design patterns allowing asynchronous functions to interact with the rest of your code.
The following are two example of callbacks, one is synchronous, one is asynchronous:
function a (input, callback) {
callback(input * 2);
}
function b (input, callback) {
setTimeout(() => callback(input *2), 100);
}
console.log('start!');
a(100, x => console.log(x));
b(1000, x => console.log(x));
console.log('end!');
The output should be:
start!
200
end!
2000
Callbacks don't make anything asynchronous but is a technique of allowing asynchronous code to interact with other parts of your code.
Promises do re-schedule your .then() callback because that's the way it was designed. But all it does is execute the .then() at the end of your code. That's all it does, it does not execute the .then() callback in a separate thread.
How does it execute your code later? Well, your code is a function. It simply calls it later. How does it call it later? It simply adds your function to a list of things that needs to be done later. At the end of your code the interpreter will check this list (or lists) to see if it needs to do anything. This part of code that checks if anything needs to be executed is called the event loop. The things in the list/lists that needs to be checked are called "tasks" or "microtasks" in the documentation.
Asynchronous functions are asynchronous. They are implemented using C/C++. So if a piece of C/C++ code uses threads or signals or async I/O it can let the javascript interpreter wait for the asynchronous results using javascript callbacks (it simply accepts a javascript function that it will call later) or promises (it returns a javascript Promise object).
So, I am currently learning about callbacks and promises and I keep getting tripped up when watching tutorials. So i thought that I would put it in an example form and see if anyone could tell me if my thinking is correct. I am currently working with MongoDB and Mongoose.
Here is an example piece of code taken from a tutorial. I believe that this is considered a callback?
user.save((err) => {
if (err) {
return res.status(400).json({
error: "You are not authorized to perform this action.",
})
});
And then this would be considered a promise?
user.save().catch(err => {
return res.status(400).json({
error: "You are not authorized."
})
})
Are there any performance advantages of using a promise over a callback or vice versa?
Thank You!
Callbacks and promises are different but share some concepts.
A callback is simply a function passed to another function as a parameter where that function can be executed at any time.
for example:
function iNeedACallback(callback)
{
// execute a bunch of code...
// use the callback function provided
callBack("a function called 'iNeedACallback'")
}
const callback = (fromFunction) => console.log("I am a callback function called from: " + fromFunction);
// Execute iNeedACallback by passing in the callback
iNeedACallback(callback);
The above code is a very simplistic instance of a callback function - now this can either be executed sequentially(like in the example above) or it can be an async operation on the event loop. (for more info about the event loop: Why do you need to await AJAX calls in JS but not in C#?)
A Promise makes use of callback functions in order to handle async code in a conventional way. The nature of a Promise infers that its some code that will be placed on the event loop as it executed asynchronously and not block any other code while waiting for an operation like a network call.
for example:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const text = "i was only called after 2 seconds :(";
resolve(text);
}, 2000)
})
promise.then((text) => console.log(text))
console.log("i got called immediately :)")
//Output:
//i got called immediately :)
//i was only called after 2 seconds :(
In the above example we give a promise a callback function to execute when an async operation has completed (like a setTimeout) where the most common use cases are network calls like HTTP requests or TCP connections to a database like mongodb.
Back to your original question - your assumption is correct in the sense that your demonstration of a callback and promise is correct, and your question about performance..
Javascript is single threaded so if your callback function is placed on the event loop (which it may or may not be) then it will not block the main execution call stack. Promises are inherently async operation so they will always be placed on the event loop so the performance factor is dependent on the underlying implementation of the callback function - Promises will be async where as some regular callbacks could be sequential and synchronous.
I have a nodejs express app and I use a library which has a typical callback interface for executing functions. My persistence layer uses a promise based approach. I have the following code which bothers me
getUserByName('dave')
.then(function (user) {
// check stuff and call the callback with success
return cb(null, true);
})
.catch((err) => cb(err, false));
Problem: the cb(null, true) functions returns undefined and the promise ends with this warning a promise was created in a handler but was not returned from it.
I can fix this by running the callback and then do return null like this:
// check stuff and call the callback with success
cb(null, true);
return null;
But now I'm asking myself is it really waiting for the callback to finish? Is this the correct way to handle this kind of warning? I have the feeling I'm doing it wrong.
I remember having the same problem when writing an express middleware and then inside a promise calling the next() function to jump to the next middleware. It also returns undefined. Any suggestions to handle this?
Well, the proper solution would of course be to switch to a framework that doesn't use node-style callbacks and leverages promises, so that you could simply return your promise and wouldn't need to call any callbacks passed to you.
If that is not possible, you still should not call such callbacks from your normal code. The warning is correct, you are calling something (the callback) that does more asynchronous work (creates other promises) but are not returning that into your chain ("forgetting" to wait for it), a common mistake. Your explicit return null suppresses this warning correctly, but there's actually a much better way:
Write your code as if you already were returning promises, and then invoke .asCallback which is dedicated for this very purpose (including not issuing warnings):
getUserByName('dave')
.then(function (user) {
// check stuff and call the callback with success
return true;
})
.asCallback(cb)
But now I'm asking myself is it really waiting for the callback to
finish? Is this the correct way to handle this kind of warning? I have
the feeling I'm doing it wrong.
The Javascript execution in node.js is single threaded so the code is waiting for any synchronous code in cb() to finish. If cb() does async operations (which the warning you are getting makes me think it is), then your code is NOT waiting for those asynchronous operations to finish.
Whether or not your work-around is the correct way to handle that warning depends upon what is happening in the callback and whether your code needs to wait for any async operations in that callback to actually complete. If your code does not need to wait for them, then adding the empty return is perfectly fine and just tells the promise library that you are purposely not returning a promise that was created inside the .then() handler which is an OK thing to do in some circumstances.
If, on the other hand, you do need to wait for the asynchronous operations inside of the callback to complete, then you need the callback's help in order to be able to do that by making it either return a promise or for it to have a completion callback itself (though the promise would be a lot easier in this case).
There are many questions on making a Nodejs/Javascript method synchronous, but the answers I have seen so far involved using libraries such as async and fibrous.
But to use libraries such as fibrous, I have to wrap my function with their wrapper.
I am seeking a solution where the code lies within my function (not outside and wrapping it).
For example, this is my async function which uses a callback:
function myFunc(callback) {
// Classic database fetch which is asynchronous
db.find("foo", function(err, results) {
callback(err, results);
});
}
What I want is for the function to return the results:
function myFunc() {
// Make this function synchronous, and return the result
// ...
return results;
}
How do I do that?
Once again, I don't want to wrap myFunc with other functions. I am thinking if a sleep loop works?
No, you can't use a loop to wait for an asynchronous call. Javascript is single threaded, so you need to return control to the main event handler for the asynchronous callback to be called. If you run a loop, the event that the database query is completed will just wait in the queue and never be handled.
What you can do is to return a promise instead of the result itself. That's an object that keeps track of whether the callback has been called or not, has a property where the callback can put the result, and has a method for getting the result when you need it (which uses a callback, because once you use an asynchrous method it can't be handled completely syncronously).
If you want an actual return value from an asynchronous function, you have no other choice than using either generators or Promises.
You will always have to wrap your functions, or return Promises directly.
One of the best promise libraries out there is bluebird, which also has an explanation for how and why to use it (https://github.com/petkaantonov/bluebird#what-are-promises-and-why-should-i-use-them). If you need to interface with node style callbacks or need to expose an API that relies on node style callbacks instead of promises, it also comes with some convenience methods for automating that conversion.
I'm trying to work out how I can do my JavaScript callbacks in a different style.
My current style of callback, passes the callback into the function, and the function calls the callback. For example:
Function call
doSomething(function(data){
console.log(data);
});
Function
function doSomething(callback) {
// Call the callback
callback("someData");
}
This is the current style of callback that I'm using. But I've seen libraries that do their callbacks in a different style. For example:
Function call
doSomething().success(function(data){
console.log(data);
});
How does this work, and could anybody outline a simple example for me? Thanks for your time.
That is an implementation of the promise library. jQuery has an implementation called deferreds and another one is Q.
doSomething would look like something like this, using jQuery.
function doSomething() {
var dfd = $.deferred();
// do your logic
// eventually call dfd.resolve();
return dfd.promise();
}
Then calling it, use
doSomething().then(function() {
// do something else
});
What is nice about this pattern, is that you can have multiple callbacks and error callbacks.
The style that you're describing is generally called promises. jQuery has promises, but their documentation calls them "Deferreds" and it is an implementation of the Promises/A spec; there are a couple other promises libraries out there, including Q. (YUI also contains a promises implementation.)
There have been a bunch of recent (mid-2013) blog posts about promises, so it should be easy to find more information about them, both as a pattern and about specific implementations. It's worth digging into the source code of a couple of the implementations to see the nuts-and-bolts, but at a high-level, you can think of promises like this:
You wrap an asynchronous function in a promise and it is called.
The promise itself is then returned, meaning that you can save a reference to it in a variable.
The promise itself will be resolved (or "fulfilled") when the async function you called is complete.
You can then call done on the resolved promises, passing your callback function as the argument to done.
Isn't it simply this here:
Function
doSomething = new Object();
doSomething.success = function(callback) {
// Call the callback
callback("someData");
}
So it is just an Object extended with a member "success" that is a function.