I want to convert the below callEndPointWrapper to return a Promise instead of callback.
I have tested with the below code, but awaiting on Promise for callEndpointWrapper() the request is timing out.
Am I missing any thing below?
(While debugging I see the request times out on below line of code while awaiting for Promise:
return (function callEndpoint(callback): any {
CallBack:
function callEndPointWrapper(): any {
return function callEndpoint(callback) {
try {
// gRPC call
client[methodName](req, options, callback);
}
catch (err) {
callback(err);
}
};
}
const result = yield callEndpointWrapper();
// I get the correct result from callback above (both on success or error)
Promise:
function callEndPointWrapper(): Promise<any> {
return new Promise( (resolve, reject) => {
return (function callEndpoint(callback): any {
try {
// gRPC call
resolve(client[methodName](req, options, callback));
} catch (err) {
reject(callback(err));
}
});
});
const result = await callEndpointWrapper();
// Above request times out.
The desired result of callEndPointWrapper seems to be a function (callEndPoint) that does some asynchronous work which you can further invoke to do something.
In your callback approach you are producing this callEndPoint function.
----> callEndPointWrapper returns callEndPoint which does async work.
In your promise based approach on the other hand, you are attempting to produce the result of callEndPoint rather than return callEndPoint itself. In fact, callEndPoint is never invoked within the Promise constructor.
----> callEndPointWrapper returns a promise which never resolves and internally creates the callEndPoint function that does nothing because it's never invoked.
It's important to note that a single call to callEndPointWrapper is not async. The actual async part (assuming client methods are async) happens in callEndpoint so an async invocation for your callback-based approach would be something like:
callEndPointWrapper()(
function callback(responseFromEndpoint) {
// ...
}
)
// or something like
let caller = callEndPointWrapper();
caller(function callback(responseFromEndpoint) {
// ...
});
From this follows that the promise based approach would require two invocations as well:
await callEndPointWrapper()(); // call a wrapper which returns a function which returns a promise
A functionally equivalent (in terms of the produced result) promise-based code for your callback code is the following:
function callEndPointWrapper(): any {
return function callEndpoint() {
return new Promise((resolve, reject) => {
try {
client[methodName](req, options, (err, result) => {
if (err) return reject(err);
resolve(result);
});
} catch (err) {
// Note: this rejection will only happen on any sync errors
// with the above code, such as trying to invoke a non-existing
// method on the client. This type of error is a programmer error
// rather than an operational error in the system so you should
// consider if such errors should even by caught by your code.
reject(err);
}
});
};
}
However, this leads to the question of what's the point of having the wrapper function at all if you're not passing any config options to be available in the closure of the callEndpoint function?
Based on your example usage, all you need is the callEndpoint method.
It comes to mind that you might be using something like co which allows you to yield functions (thunks) and invokes them internally with a callback.
So when you do
yield callEndpointWrapper()
you are actually calling
yield function callEndpoint(callback) {
// ...
}
And then co does some magic under the hood for you.
This is a pattern that is deprecated by co and is overall ill-advised to use. Not to mention that it's very confusing (and ugly IMHO) behavior that requires knowledge of the particular library.
To use promises with co, you don't need the wrapper function. Just yield or await the result of calling callEndPoint (the same one from my promise example above), which will be a promise.
yield callEndPoint()
// or
await callEndPoint()
Related
I am currently learning javascript and i find this often on tuitorials i watch. Javascript automatically pass the result of a function as a parameter to the next function.
fetch('SampleApi')
.then( function(data) { return data.json() } )
.then( function(data) { console.log(data.name); } )
.catch(function(err) { console.log(error) })
the result of the fetch goes directly as a parameter to the function then the result of the function goes directly as a parameter to the next function.
I just want to know what is this and what is this called. I need to understand this before diving deep.
EDIT: modified example to show passing parameters between methods to directly answer the qeustion.
The underlying premise is that JavaScript can act upon a returned result immediately as long as the operation requested is sane and available. A simple example is shown here:
console.log("|" + " This is a string with extra spaces ".trim() + "|");
This can be accomplished in your own code as well. In the following example, note the return of the operation is the object itself. This allows us to carry out any operation available within that object upon the return from some other operation in the same object:
class Test {
sayHi(message = "Passed Message") {
console.log('parameter: ' + message);
this.message = message;
return this;
}
sayBye(cb) {
cb(this.message);
return this;
}
}
const test = new Test();
test.sayHi("hello!").sayBye(passed => console.log('passed in: ' + passed));
So throughout your experience with JavaScript you will find many instances of this idea that is called method chaining.
In the example you provided, it is simply this concept applied to the fetch API.
It's called function chaining.
The fetch function returns an object that has a function then, which accepts a function as its parameter.
When then is called, it executes the given function with the data stored within the object as a parameter, and stores the return value as the new internal data, which is passed to the function in the second then call. then returns the same object that was returned from fetch.
The call to catch will check if an error was encountered (and stored into the object), and if so, will call the given function with the error.
You could spread out the whole thing, without chaining:
var o = fetch('SampleApi');
o = o.then(function(data) { return data.json(); });
o = o.then(function(data) { console.log(data.name); });
o.catch(function(error) { console.log(error); });
The short answer is "That's just how promises work"
To better illustrate WHY this is good behavior:
function getOrganizedData() {
return fetch("somedata").then(function(rawData) {
// do some stuff
return organizedData;
});
}
Anyone using this function will be able to use the organizedData - so if you have a shared service, only that service needs to know how to translate rawData into organizedData for the rest of the application to use.
What if that's not the behavior you want?
Easy, just don't chain the promises:
const fetchPromise = fetch('SampleApi');
fetchPromise.then( function(data) { return data.json() } );
fetchPromise.then( function(data) { console.log(data.name); } );
fetchPromise.catch(function(err) { console.log(error) });
But wait, won't I get errors with that approach because the catch isn't applied to each chain?
Yes! So, you need to catch BOTH chains:
const errorFunction = function(err) { console.log(error) };
const fetchPromise = fetch('SampleApi');
fetchPromise.then( function(data) { return data.json() } ).catch(errorFunction);
fetchPromise.then( function(data) { console.log(data.name); } ).catch(errorFunction);
NOTE: This chaining behavior applies to .catch as well:
fetch("somethingThatWillError")
.then(function() { console.log("THEN - I will not run because there's an error"); })
.catch(function() { console.log("CATCH - I will run because I am handling the error"); })
.then(function() { console.log("THEN - I will run because the error has been handled"); })
.catch(function() { console.log("CATCH - I will not run because there is no error to handle"); })
Edit : For resume, the result of fetch is the first data in case of success, the second data is the return of the first then and err the result of fetch in case of reject.
You are actually playing with promise here, you can look some documentation about Promise here.
In javascript your running task can be synchronous or asynchronous, promise is for handling asynchronous task. You can know more about asynchronous here.
To be quick and simple a promise can be resolve now, in ten minutes or never. When you are building a Promise, you need an executor which is passed with two arguments, a resolve function and a reject function, they will be call just before the final resolution of your promise, (after an API call for exemple).
The reject gonna be call if your promise fail (timed out on your api call for example) and the resolve gonna be call on the success of your promise. In this two callbacks (resolve and promise), if you don't know about callback you have to learn it here, you will have an argument with the return of the resolution of your promise, for example if the promise is rejected you gonna have the reason in a message and in the resolve you gonna have the data that you need from your api call.
In your case, the fetch is build like fetch = new Promise(...); where then(...) is the success resolver and catch(...) the rejected resolver. You can have a finally(...) which is called after the then() and catch().
And the data in your example is the result of your promise if it's a success and err is the result in case of error result.
Assume the scenario where you have to call an asynchronous function, but you are not really interested about success/failure situation of that function. In that case what are the pros and cons in following two patterns stated below with respect to call stack, callback queue and event loop
Pattern-1
async setSomething() {
try {
set(); // another async function
} catch (err) {
// log the error here
}
return true;
}
Pattern-2
async setSomething() {
try {
await set(); // another async function
} catch (err) {
// log the error here
}
return true;
}
Pattern 1 does not catch any errors that may occur during asynchronous operations in the set function - any errors will result in an unhandled Promise rejection, which should be avoided. Pattern 1 will only catch errors that occur during set's synchronous operations (such as, when setting up a fetch request), which are not likely to occur in most situations.
Example:
// open your browser's console to see the uncaught rejection
const set = () => new Promise((_, reject) => setTimeout(reject, 500));
async function setSomething() {
try {
set(); // another async function
} catch (err) {
console.log('err');
}
return true;
}
setSomething();
So, pattern 2 is likely preferable. If you don't care about the result of the asynchronous call, then don't await or call .then when you call setSomething().
Or, for something this simple, you might consider using Promise methods only, no async function needed:
const setSomething = () => set()
.catch((err) => {
// log the error here
});
This answer is a rather unconventional advice to the question than an actual answer to the examples posted by OP.
not really interested about success/failure situation of that function
If the above statement is the case, then it means, the return is not dependent on the result of the async invocation.
When you're not bothered about the return of the async invocation, it's better off to not use async/await or any type of promise at all. You could just invoke the function like any other function and process with the rest of the code.
I've been trying to get a conceptual understanding of why the following code doesn't catch the throw. If you remove the async keyword from the new Promise(async (resolve, ... part then it works fine, so it has to do with the fact that the Promise executor is an async function.
(async function() {
try {
await fn();
} catch(e) {
console.log("CAUGHT fn error -->",e)
}
})();
function fn() {
return new Promise(async (resolve, reject) => {
// ...
throw new Error("<<fn error>>");
// ...
});
}
The answers here, here, and here repeat that "if you're in any other asynchronous callback, you must use reject", but by "asynchronous" they're not referring to async functions, so I don't think their explanations apply here (and if they do, I don't understand how).
If instead of throw we use reject, the above code works fine. I'd like to understand, fundamentally, why throw doesn't work here. Thanks!
This is the async/await version of the Promise constructor antipattern!
Never ever use an async function as a Promise executor function (even when you can make it work1)!
[1: by calling resolve and reject instead of using return and throw statements]
by "asynchronous" they're not referring to async functions, so I don't think their explanations apply here
They could as well. A simple example where it cannot work is
new Promise(async function() {
await delay(…);
throw new Error(…);
})
which is equivalent to
new Promise(function() {
return delay(…).then(function() {
throw new Error(…);
});
})
where it's clear now that the throw is inside an asynchronous callback.
The Promise constructor can only catch synchronous exceptions, and an async function never throws - it always returns a promise (which might get rejected though). And that return value is ignored, as the promise is waiting for resolve to be called.
because the only way to "communicate" to the outside world from within a Promise executor is to use the resolve and reject functions. You could use the following for your example:
function fn() {
return new Promise(async (resolve, reject) => {
// there is no real reason to use an async executor here since there is nothing async happening
try {
throw new Error('<<fn error>>')
} catch(error) {
return reject(error);
}
});
}
An example would be when you want to do something that has convenient async functions, but also requires a callback. The following contrived example copies a file by reading it using the async fs.promises.readFile function with the callback based fs.writeFile function. In the real world, you would never mix fs functions like this because there is no need to. But some libraries like stylus and pug use callbacks, and I use something like this all the time in those scenarios.
const fs = require('fs');
function copyFile(infilePath, outfilePath) {
return new Promise(async (resolve, reject) => {
try {
// the fs.promises library provides convenient async functions
const data = await fs.promises.readFile(infilePath);
// the fs library also provides methods that use callbacks
// the following line doesn't need a return statement, because there is nothing to return the value to
// but IMO it is useful to signal intent that the function has completed (especially in more complex functions)
return fs.writeFile(outfilePath, data, (error) => {
// note that if there is an error we call the reject function
// so whether an error is thrown in the promise executor, or the callback the reject function will be called
// so from the outside, copyFile appears to be a perfectly normal async function
return (error) ? reject(error) : resolve();
});
} catch(error) {
// this will only catch errors from the main body of the promise executor (ie. the fs.promises.readFile statement
// it will not catch any errors from the callback to the fs.writeFile statement
return reject(error);
// the return statement is not necessary, but IMO communicates the intent that the function is completed
}
}
}
Apparently everyone says this is an anti-pattern, but I use it all the time when I want to do some async stuff before doing something that can only be done with a callback (not for copying files like my contrived example). I don't understand why people think it is an anti-pattern (to use an async promise executor), and haven't seen an example yet that has convinced me that it should be accepted as a general rule.
I've been trying to get a conceptual understanding of why the following code doesn't catch the throw. If you remove the async keyword from the new Promise(async (resolve, ... part then it works fine, so it has to do with the fact that the Promise executor is an async function.
(async function() {
try {
await fn();
} catch(e) {
console.log("CAUGHT fn error -->",e)
}
})();
function fn() {
return new Promise(async (resolve, reject) => {
// ...
throw new Error("<<fn error>>");
// ...
});
}
The answers here, here, and here repeat that "if you're in any other asynchronous callback, you must use reject", but by "asynchronous" they're not referring to async functions, so I don't think their explanations apply here (and if they do, I don't understand how).
If instead of throw we use reject, the above code works fine. I'd like to understand, fundamentally, why throw doesn't work here. Thanks!
This is the async/await version of the Promise constructor antipattern!
Never ever use an async function as a Promise executor function (even when you can make it work1)!
[1: by calling resolve and reject instead of using return and throw statements]
by "asynchronous" they're not referring to async functions, so I don't think their explanations apply here
They could as well. A simple example where it cannot work is
new Promise(async function() {
await delay(…);
throw new Error(…);
})
which is equivalent to
new Promise(function() {
return delay(…).then(function() {
throw new Error(…);
});
})
where it's clear now that the throw is inside an asynchronous callback.
The Promise constructor can only catch synchronous exceptions, and an async function never throws - it always returns a promise (which might get rejected though). And that return value is ignored, as the promise is waiting for resolve to be called.
because the only way to "communicate" to the outside world from within a Promise executor is to use the resolve and reject functions. You could use the following for your example:
function fn() {
return new Promise(async (resolve, reject) => {
// there is no real reason to use an async executor here since there is nothing async happening
try {
throw new Error('<<fn error>>')
} catch(error) {
return reject(error);
}
});
}
An example would be when you want to do something that has convenient async functions, but also requires a callback. The following contrived example copies a file by reading it using the async fs.promises.readFile function with the callback based fs.writeFile function. In the real world, you would never mix fs functions like this because there is no need to. But some libraries like stylus and pug use callbacks, and I use something like this all the time in those scenarios.
const fs = require('fs');
function copyFile(infilePath, outfilePath) {
return new Promise(async (resolve, reject) => {
try {
// the fs.promises library provides convenient async functions
const data = await fs.promises.readFile(infilePath);
// the fs library also provides methods that use callbacks
// the following line doesn't need a return statement, because there is nothing to return the value to
// but IMO it is useful to signal intent that the function has completed (especially in more complex functions)
return fs.writeFile(outfilePath, data, (error) => {
// note that if there is an error we call the reject function
// so whether an error is thrown in the promise executor, or the callback the reject function will be called
// so from the outside, copyFile appears to be a perfectly normal async function
return (error) ? reject(error) : resolve();
});
} catch(error) {
// this will only catch errors from the main body of the promise executor (ie. the fs.promises.readFile statement
// it will not catch any errors from the callback to the fs.writeFile statement
return reject(error);
// the return statement is not necessary, but IMO communicates the intent that the function is completed
}
}
}
Apparently everyone says this is an anti-pattern, but I use it all the time when I want to do some async stuff before doing something that can only be done with a callback (not for copying files like my contrived example). I don't understand why people think it is an anti-pattern (to use an async promise executor), and haven't seen an example yet that has convinced me that it should be accepted as a general rule.
I'm currently writing a couple of functions which work async.just imagine this example
signUpUser(userInfo, callback) //callback(err, token)
createToken(userInfo, callback) // callback(err, token)
now I'm wondering whether to return the callbacks or just call'em inside my functions, I mean for example in the createToken:
createToken(userInfo, callback) {
var token = ...;
callback(err, token); //or
return callback(err, token);
}
cause as long as the callback belongs to another programer and if for what ever reason he decides to return something in his code this simply blocks it.
EDIT:After I posted my question I got the answer that it's not possible to return anything but as I went deeper in my codes and also node js I found the opposite.the code below runs well!!
function foo(a, callback) {
console.log(a);
return callback(a);
}
function bar(a) {
return a;
}
console.log(foo(3, bar));
You've said your functions are asynchronous. That means they can't return the result of calling the callbacks, because they return before the callbacks are ever called. So they should return nothing or some useful context value, but not the result of calling the callback. So of the two choices in your question:
function createToken(userInfo, callback) {
startAsyncProcess(function() {
// It's done, may have failed (err), may have succeeded (token)
callback(err, token);
});
}
Separately and a bit off-topic: Look at using promises rather than manual callback mechanisms (unless of course the manual style is to fit into a large established codebase). E.g.:
function createToken(userInfo) {
return new Promise(function(resolve, reject) {
startAsyncProcess(function() {
if (/*...it succeeded...*/) {
resolve(token);
} else /* ...it failed... */ {
reject(err);
}
});
});
}
(Of course, if startAsyncProcess provides a promise, you'd use that promise.)
Usage:
createToken(/*...info...*/)
.then(function(token) {
// It worked, use the token
})
.catch(function(err) {
// It failed
});
If you returned the callback, so how you will now that the execution of the async class finished?
That's why we send the callback to the asyc work, to call it after finishing its functionality or getting the response from the server.
You can use Promises, and here the MDN documentation.
The idea behind the promise, it you return an object that has methods for each case of your async action like fulfilled, and rejected