Sorry for the Noob Question. I'm trying to write a node.js function called "getTransitionId" that uses the jira-connector plugin to retrieve data for possible transitions for a particular issue.
The getTransitions function from the jira-connector takes two parameters: an object with the parameters of the ticket, and a function to execute once the call is finished.
Here's my problem: for reasons beyond the scope of this question, I want to access this data outside the function that's being passed as parameter to "getTransitions." But I can't figure out how. I understand that the last return statement (return "transitionData") is returning "undefined" because it's executing a return statement before the call is finished, but I don't know how to fix that.
Can I correctly use a callback in this case? If so, how would I use it in a function that is being passed as a parameter to another function?
const JiraApi = require('jira-connector');
const jira = new JiraApi( {
host: //Jira URL
basic_auth: {
//Authentication Information
}
});
function getTransitionId (ticketNumber, transition) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
const transitionData = transitions['transitions'];
});
return transitionData;
}
Thanks for the help. Hope this made sense.
You could make your own getTransitionId function take a callback function as an argument. Here's an incomplete example (see ahead):
function getTransitionId (ticketNumber, transition, callback) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
const transitionData = transitions['transitions'];
const id = /* ..get ID fron transitionData, somehow.. */
callback(id);
});
}
// Called like this:
getTransitionId(ticketNumber, transition, function(id) {
console.log("Got the ID:", id);
});
This isn't perfect, though. What if getTransitions has an error?
When you call jira.issue.getTransitions, you pass a callback function which takes two parameters: error and transitions. This is standard for functions which take callbacks in JavaScript - that is, callbacks usually take an error parameter (null or undefined if there was no error) and a data parameter (containing results of the action, like fetched transitions or an id).
We can change getTransitionId to take an error and then pass the error to the callback that you gave to getTransitionId:
function getTransitionId (ticketNumber, transition, callback) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
if (error) {
callback(error);
return;
}
const transitionData = transitions['transitions'];
const id = /* ..get ID fron transitionData, somehow.. */
callback(null, id);
});
}
(Note that we use a return; statement inside if (error) -- that's so that we don't continue and try to use the transitions argument, which is probably undefined, since there was an error in jira.issue.getTransitions. This also prevents callback from being called a second time.)
Since we've added an error argument, we need to change how we call getTransitionId:
getTransitionId(ticketNumber, transition, function(error, id) {
if (error) {
console.error("There was an error fetching the transition ID:", error);
return;
}
console.log("Got the ID:", id);
}
(Since we do callback(null, id); in the code for getTransitionId, error will be null, so the code in if (error) { won't run. Of course, if there is an error, if (error) { will be run, and that's what we want!)
By adding code to handle errors passed to your callbacks, you make your code safer. Contrastingly, if you ignore error, you might end up having errors in your code that are hard to find - for example, you might have a TypeError because transitions is undefined, or see "Got the ID: undefined" in the log!
Related
I have trouble understanding the callback function with an parameter of err(error) I complete understand the callback function but find this specific topic a bit hard to understand because I don't know why and how a value or something is passed into the function without me calling the function and sending anything as parameters.so this is my first question.
My second question is :
I've been trying to use
object.insertMany([object1,object2],function(err) {
if (err) {
console.log(err);
}
So I noticed something about these kind of callback function such as
document.querySelector("#class").keypress(function(evt){
})
where I only use them when something triggers them, so is it true that I can only use those kind of functions such as function(err) or function(evt) in specific cases like those and I can not make a function with the err parameter such as this
function addition(x,y){
var result =x+y;
return result;
}
addition(1,2):
In your first couple of examples the insertMany and keypress functions are responsible for supplying the callback function with a parameter. (there isn't anything special about err or errors, the functions would pass the error like you would any other parameter)
If want to write a function that supplies a parameter to a callback you definitely can!
function addition(x,y, callback){
var result =x+y;
var error = isNaN(result) ? 'Bad input!' : undefined;
callback(result, error);
}
addition(1, 2, function(res, err) {
console.log(res);
if(err) {
console.log(err);
}
});
addition('apple', 2, function(res, err) {
console.log(res);
if(err) {
console.log(err);
}
});
I have a function with a callback, my problem is that the return of the function happens before the callback ad then return null instead of returning me the array of coordinates
function callback(coordinates=[]){
console.log(coordinates);
return coordinates;
}
function getCoordinates(callback){
connection.connect();
let coordinates=[null];
connection.query('SELECT AreaId AS areaNumber, longitude AS longitude, latitude AS latitude FROM coordinates', function (error, results, fields) {
if (error) throw error;
let area=[];
for (result of results) {
if (!area.includes(result.areaNumber)){
area.push(result.areaNumber)
coordinates[result.areaNumber]=[];
}
coordinate=[result.longitude,result.latitude];
coordinates[result.areaNumber].push(coordinate);
}
coordinates=callback(coordinates)
});
connection.end();
return coordinates;
}
console.log(getCoordinates(callback));
and I have :
[null] //correspond to console.log(getCoordinates(callback));
and
[array with value] // corresponding to console.log(coordinates) in function vallback
How to do for that my callback will be considered?
Sorry I am kind of new on node.js so I may have missunderstood callback.
What I would like is to get an array of coordinates that I can use later on at 2 different places in my code like :
.get('/map', function(req, res) {
let Coords=getCoordinate(callback)
res.render('map.ejs', {token: tokenMapbox, coordinates: Coords});
})
.get('/wmap', function(req, res) {
let Coords=getCoordinate(callback)
res.render('wmap.ejs', {token: tokenMapbox, coordinates: Coords});
})
There are several approaches to this problem, however if you wish to use the resulting coordinates in a similar way to synchronous code, I suggest you try using the async/await syntax. If you call your query from an async function you can use the await keyword to provide more readable code.
Once you have your coordinates variable populated in your async function you can do what you wish with it.
For example:
function getCoordinates() {
connection.connect();
let coordinates = [];
return new Promise((resolve, reject) => {
connection.query('SELECT AreaId AS areaNumber, longitude AS longitude, latitude AS latitude FROM coordinates', function (error, results, fields) {
if (error) {
reject(error);
} else {
let area=[];
for (result of results) {
if (!area.includes(result.areaNumber)){
area.push(result.areaNumber)
coordinates[result.areaNumber]=[];
}
coordinate=[result.longitude,result.latitude];
coordinates[result.areaNumber].push(coordinate);
}
resolve(coordinates);
connection.end();
}
});
})
}
async function testCoordinates() {
let coordinates = await getCoordinates();
console.log("Coordinates:", coordinates);
// You can do whatever you wish with the coordinates variable
}
testCoordinates();
You're confusing different things. Let me explain
First thing, forget about the term "callback". We'll understand this simply as a function passsed as parameter to another function. Don't worry about it, I'm going to explain.
So we start from the problem: how to fetch array of coordinates from database and print it
Next thing you get to know about interacting with database and assuming this is how your library works: it has a function connection.query(myQuery, someFunction) which can get you results from database.
Now first thing you notice about that query function is it's parameters. myQuery is a string and someFunction is a function definition. While we have seen in other languages that we pass values such as numbers, string, etc. as parameters to a function, interestingly in javascript you can pass on a function definition as a parameter as well. And this is what makes javascript powerful, you can pass on function definition as parameter.
Wow, passing on function as parameter, but how does that work?
Let's take a different example; let's say here I want to create a function which will do some calculations
//Here myVar is a variable and doSomething is a function
function interestingJsFunction(myVar, doSomething){
var twiceOfVar = 2*myVar;
doSomething(twiceOfVar);
var thriceOfVar = 3*myVar;
doSomething(thriceOfVar);
}
So what does this function do? It applies some calculations and calls the function doSomething at some points; at one point it passes twice value of myVar to function and at one point it passes thrice of myVar. But what this function doSomething do is not defined as of now. And you can define it by passsing your own function as parameter. This gives you infinite possibilities. How?
interestingJsFunction(2, function(result){ console.log(result) })
interestingJsFunction(2, function(result){ console.log("the new behaviour" + result) })
//And so on...
You understand how this has made one interestingJsFunction useful in different cases. If you knew that you would need only one implementation of doSomething(), you could have simply removed the doSomething from parameters and whatever you wanted to do, you could have done that directly inside interestingJsFunction(e.g. console.log(twiceOfVar))
Now coming back to the query function. It is also an interestingJsFunction and if you go to definition of query function(you can dig up the code of your library to see what's inside query function) you'll find that it does some operations on database, gets the results and call the function[similar to doSomething] which was passed as parameter, if it gets any error while doing so, it calls the function in parameter and passes error to it.
When it does so, it sends back error, results and field as parameter to this function. So now you can utilize these paramaeters in your function which was passed as parameter. It's upto you now how you want to utilize this, it could be that you can simply print the results as following (remember how we used interestingJsFunction?)
//We could simply print the results if there are any
connection.query(myQuery, function(error, results, fields){
if(results) console.log(results.toString())
})
//Or we could throw erorr if there's any
connection.query(myQuery, function(error, results, fields){
if(error) throw error
})
//Guess what would happen when you return something inside this function?
var myQueryFunction = connection.query(myQuery, function(error, results, fields){
return "return of query function"
})
//And guess what would happen when you have something like this
function myNewFunction(){
var x = connection.query(myQuery, function(error, results, fields){
return "return of query function"
})
return "return of myNewFunction"
}
I leave last 2 exercises for you and you should be able to fix the problems after that. Try console.log statements to understand
begginer in Javascript and Node Js here.
While trying to do my first, simple update function, i got the error :
TypeError: callback is not a function.
I searched for the answer online but this problem is still a mistery.
function UpdateProductsCodes(columns, returnColumns, type, callback) {
for (var i = 0; i < columns.ids.length; i++) {
updateSql = "UPDATE TProductCodes SET code =?, product_id =? OUTPUT inserted.id, inserted.code, inserted.product_id INTO #returnValues WHERE ids =?";
var params = [];
params.push(columns.codes[i]);
params.push(columns.product_ids[i]);
params.push(columns.ids[i]);
sql.query(conn_str, updateSql, params, function (err, products, more) {
//Code stops here
//TypeError: callback is not a function
if (err) {
callback(err, null);
return;
};
if (!more) {
callback(null, products);
}
});
}
}
This function should do a simple update, nothing more. Its used here:
UpdateProductsCodes(req.body.entities, conditions, returnColumns, type, function (err, products) {
if (err) {
console.dir(err);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.write(JSON.stringify(utils.GenerateResponse(err.message, true, 'JSON')));
res.end();
return;
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify(utils.GenerateResponse(products, false, type)));
res.end();
});
The problem is that you are simply sending the wrong number of arguments when you call the function.
The function accepts four inputs: columns, returnColumns, type, callback. But in your example, you are sending five inputs: req.body.entities, conditions, returnColumns, type, function (err, products)
The last one (the function, in this case) is therefore ignored. The value which the function is receiving as being the callback value is in fact the one you've named type when you call the function, because that's the fourth argument you provide. This value is not an executable function - which is what the error message is telling you.
Now I don't know which values are the ones you actually need/want to send to the function, but clearly one of them is redundant and you need to remove it from the calling code. Based purely on the names, I'd guess that one of either req.body.entities or conditions is not needed, but of course I can't see what those variables contain, and I can't be certain of your intent, so you'll have to work it out yourself.
P.S. I also note that your function never actually uses the returnColumns or type parameters which it receives, so you maybe should consider whether you actually need to accept these at all. Perhaps they can be removed.
The following code supposed to be update username in the data base then retrieve updated username.
updateUserMame and getUserName are two different REST calls.
updateName(name) {
var obj = this;
if (name === 'None') {
name = null;
}
obj.UtilityService.updateUserName(name, obj.userId)
.success(function (data) {
if (data) {
obj.getUserName(obj.userId);
console.log('Name is updated for ID:'||obj.userId);
} else {
console.log('Something Wrong');
}
});
}
getUserName(userId){
obj.UtilityService.getUserName(userId)
.then(function (result) {
console.log(result.user.userId);
}
}
I have user name 'Nathan Drake' in the dataBase.
When I run the update function with 'Elena Fisher', it is returning 'Nathan Drake'.
I've read some articles to make synchronus service calls, but unable to figure out what is going wrong.
Please help.
You could wrap your update function in a promise:
var updatePromise = $q.when(updateName(name)); // creates a promise
When your promise has finished processing, you can resolve it using then() which takes a success callback and an error callback
updatePromise().then(function successCallback(response){ // resolves the promise using then
getUserName(userId) // execute the rest of your code
},
function errorCallback(response){
console.log(error)
});
You would need to inject $q into the scope you are working with
Your code does not make much sense, that is I see possible mistakes as it looks like you are interchanging user name and user id and calling the obj context from inside a function even when its not declared there etc. Either we are missing code or this will fail when you try to run it.
Here is your example with some fixes and comments that show how you could do it using callbacks (no sync code, as mentioned by everyone else on this thread you should avoid actually waiting for I/O and use callbacks instead).
updateName(name) {
var obj = this; // good, you captured this
if (name === 'None') {
name = null;
}
obj.UtilityService.updateUserName(name, obj.userId)
.success(function (data) {
if (data) {
// ok, you successfully updated the name so why would you go back to the server and get it again? You know the value based on your update.
console.log('Name is updated for ID:' + obj.userId.toString());
// for your example though here is how you could handle it
obj.getUserName(obj, obj.userId, function(user){ // i assumed the name is stored in variable userName
console.log('Name from server = ' + user.userName); // no idea what you are returning but you can figure it out from here
// maybe you also want to capture it again??
obj.name = user.userName;
});
} else {
console.log('Something Wrong');
}
});
}
// pass in captured this as obj, the user id, and a callback
getUserName(obj, userId, callback){
obj.UtilityService.getUserName(userId)
.then(function (result) {
callback(result); // call the callback with the result. The caller can then do something with it
}
}
As a novice in Javascript, I'm confused on which could be the best way to differentiate between the result computed by an asynchronous function, and any exception/error.
If I'm right, you cannot use try-catch in this scenario, as the called function
ends before the callback, and it is this latter who actually may throw an exception.
Well.
I've seen so far some library functions expecting a callback like: function(err, result).
So, one have to test err before using result.
Also I tried myself to return either the actual result or an Error object.
Here, the callback is of the form function(result)
and you have to test result instanceof Error before using it.
It follows an example of this:
function myAsyncFunction ( callBack ) {
async_library_function( "some data", function (err, result) {
if (err) { callBack ( new Error ("my function failed") ); return; }
callBack ( some calculation with result );
});
} // myFunction ()
//
// calling myFunction
//
myAsyncFunction ( function (result) {
if (result instanceof Error ) { log ("some error occurred"); return; }
log ("Alright, this is the result: " + result);
});
What is the best (maybe the common) way to do this?
Thanks.
There are three main approaches that I've been using myself:
Having an "error" parameter passed to the callback.
Having an "error" callback. This is usually combined with (1).
Having some sort of global exception manager.
I'll start with the third one. The idea is to have an object that will allow dispatching errors as well as catching them globally. Something like this:
var ErrorManager = {
subscribers: [],
subscribe: function (callback) {
this.subscribers.push(callback);
},
dispatchError: function (error) {
this.subscribers.forEach(function (s) {
s.apply(window, [ error ]);
});
}
}
This is quite specific to a given situation because there's basically no easy way of tracking the origin of an error as well as it's easy to mess up with this. For example, if you need to hide a dialog box whose contents failed to load, you'd have to propagate this information (e.g. dialog box Id/element) to all the subscribers.
The above approach is good when you want to execute an action that doesn't alter (or alters an independent part) of the web application (e.g. displays a status bar or a message to a console).
The second approach basically makes a separation between successful call and a failure. For example:
$.ajax('/articles', {
success: function () { /* All is good - populating article list */ },
error: function () { /* An error occured */ }
});
In the above example, the success callback is never executed in case of a failure so if you want to have some default behavior to always trigger, you'd need to either sync between the two callbacks or have a callback that is always called (for the above example - complete).
I personally prefer the first approach - having a callback where you have an error object passed along with potential result. This eliminates problems with having to "track" the origin/context on an error as well as worrying about the clean-up procedure (default behavior). So, something like you provided:
function beginFetchArticles(onComplete) {
$.ajax('/articles', {
complete: function (xhr) {
onComplete(xhr.status != 200 ? xhr.status.toString() : null,
$.parseJSON(xhr.responseText)); /* Something a bit more secure, probably */
}
});
}
Hope this helps.
It depends vastly on your implementation. Is this a recoverable error? If it isn't, then the way you are suggesting should work just fine. If it is recoverable then you shouldn't be returning an error. You should be returning an "empty" result. Keep in mind maintainability as well. Do you want instanceof checks throughout the code? Also, I know some programmers like that JavaScript is loose with types, but you run into consistency issues when the expected object passed through can actually be unexpected. Is it a result, or an error, or even something else altogether?
That's one way to do it. Though I'd usually leave any manipulations/processing of the result to the callback function.
Another way is you can pass back both the error and result values to the callback:
callback (err, result); \\ if no error, err = null, if no result, result = null
Alternatively, you can ask for separate error and success callbacks:
function myAsyncFunction ( successCallBack, errorCallBack ) {
\* ... *\
}
And then trigger the appropriate function depending on the received response.
One approach can be like this:
function Exception(errorMessage)
{
this.ErrorMessage = errorMessage;
this.GetMessage = function()
{
return this.ErrorMessage;
}
}
function ResultModel(value, exception)
{
exception = typeof exception == "undefined"? null, exception;
this.Value = value;
this.Exception = exception;
this.GetResult = function()
{
if(exception === null)
{
return this.Value;
}
else
{
throw this.Exception;
}
}
};
And in your usage:
function myAsyncFunction ( callBack ) {
var result;
async_library_function( "some data", function (err, result) {
if (err)
{
result = new ResultModel(null, new Exception("my function failed"));
}
else
{
result = new ResultModel(some calculation with result);
}
callBack ( result );
});
}
myAsyncFunction ( function (result) {
try
{
log ("Alright, this is the result: " + result.GetResult());
}
catch(ex)
{
log ("some error occurred" + ex.GetMessage());
return;
}
});
If you want to make robust programs, you should use promises. Otherwise you have to handle 2 different kinds of errors which is pretty crazy.
Consider how to read a file as JSON without crashing the server:
var fs = require("fs");
fs.readFile("myfile.json", function(err, contents) {
if( err ) {
console.error("Cannot read file");
}
else {
try {
var result = JSON.parse(contents);
console.log(result); //Or continue callback hell here
}
catch(e) {
console.error("Invalid json");
}
}
});
With promises e.g:
var Promise = require("bluebird");
var readFile = Promise.promisify(require("fs").readFile);
readFile("myfile.json").then(JSON.parse).then(function(result){
console.log(result);
}).catch(SyntaxError, function(e){
console.error("Invalid json");
}).catch(function(e){
console.error("Cannot read file");
});
Notice also how the code grows vertically like with synchronous code instead of horizontally.