Queuing asynchronous promises - javascript

I'm using promises to query a rest api (using httpplease with the Promise plug-in):
api.call = function (myurl) {
return http.get({
"url" : myurl
});
}
This returns a promise that I can use with something like:
api.call (myurl)
.then (function (resp) {
// do whatever with the data
});
Now I'm trying to authenticate the api connection and for this I need to queue 2 async calls to the rest api:
1.- Ask for an authentication token
2.- Use the authentication token to make the actual call:
var getToken = function () {
var tokenUrl = "....";
return http.get({
"url": tokenUrl;
})
}
api.call = function (myurl) {
return getToken().then(function (token) {
return http.get({
"url" : myurl,
"headers" : {
"auth-token": token
}
})
})
}
The client code would remain the same:
api.call (myurl)
.then (function (resp) {
// do whatever with the data
});
Unfortunately, the code above is returning the final promise before the first one finishes (ie, token is undef in the final "then").
I'm probably missing something, but I thought that this should work after reading this:
"If you return a value, the next "then" is called with that value.
However, if you return something promise-like, the next "then" waits
on it, and is only called when that promise settles (succeeds/fails)"
Any idea how to do this?
M;
EDIT: Fixed typo in code

Related

How to execute asynchronous code in Javascript

I've looked into MDN web docs article on async functions and for some reason it doesn't work for me
Here's my code
function createObject() {
try {
console.log("Processing POST Loan.");
var data = {
"value1" : 1288,
"value2" : [{
"value3" : 3833,
"value4": [{
"value5": new Date()
}]
}]
}
var auth = Buffer.from("login:pass").toString('base64')
const res = request("http://url.com/resource", {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Authorization': "Basic "+auth
},
body: JSON.stringify(data)
}, function(error, response, body){
//console.log(response + ' '+body)
})
var response = res.body.id;
return response
}
catch(err) {
throw err
}
}
async function uploadReport() {
console.log('cerate object')
var objectId = await createObject();
console.log('object = '+objectId)
}
uploadReport()
Exactly as described in the article. But when I run my script I get this result:
cerate object
Processing POST Loan.
'data {"value1":1288,"value2":[{"value3":3833,"value4":[{"value5":"2021-10-05T09:45:46.126Z"}]}]}'
'auth '
object = undefined
Then nothing happens for a few seconds and execution stops. Http request works fine and objects are being created as I run the script, though I don't get any response (this API should return auto generated object ID). What am I doing wrong here?
I'm assuming you are quite new to JS programming and it seems you lack a little understanding about how the flow of execution works for async code.
In JS, async code works in promises. Promises are the way JS represents code that eventually will yield a value (or void, but it's the same).
So now we need a way to control the flow of execution. This means, we should be able to execute code that depends on that result after we have gotten that result. Or in other words, we should wait for the promise to resolve and then execute the code that depended on it.
Enter callbacks. Callbacks is how this is done in JS (before async/await appeared, but let's not get ahead of ourselves). As functions are first class citizens in JS we can declare them and pass them around as function arguments. So, in those terms, a callback it's the code that should be executed after the promise has given us its result.
When it comes to callbacks, me personally I have seen two ways of dealing with them.
A first approach, function expects such callback as an argument. Usually (but it doesn't have to be like this) the first arguments are the actual arguments necessary to perform the task, and the last one is the callback: what to do after the task is done. Example:
// A function that receives an `arguments` object and a `callback` function.
// Observe
function doSomethingAsynchronous(arguments, callback) {
const a = arguments.a
const b = arguments.b
const result = a + b //this is not asynchronous, only to illustrate.
callback(result)
}
You would use this function like this:
doSomethingAsynchronous({a:2, b:3}, (result)=>{
console.log(`The result was ${result}`)
})
Note how doSomethingAsynchronous does not return anything; the flow of execution is directed towards the callback.
A second approach might be a function that returns an actual Promise. Promises have a then() method and a catch() method. These are used to chain more code after the resolution of the Promise:
function iReturnAPromise(arguments) {
return new Promise((resolve, reject) => {
const result = arguments.a + arguments.b;
resolve(result);
})
}
You would manage the flow of execution by doing so:
const promiseOfTheResult = iReturnAPromise({a: 2, b:2})
promiseOfTheResult.then((result) => {console.log(result)})
// You'll never see it like that. You'll always see:
iReturnAPromise({a:2, b:3}).then((result) => {console.log(result)})
And last, but definitely not least, came async/await which simplified the use of promises. With async await, you would declare iReturnAPromise just the same, but you would use it like so;
const result = await iReturnAPromise({a:1, b:2})
console.log(result)
Notice how this last method keeps the code in line and avoids the callback hell. Also notice how functions that don't return a promise cannot be awaited, they first have to be "promisified": that is, wrapping them in a promise.
Let's start from the begining since you seem a little confused.
What you want to do is to make an async call from a callback kind of function ('request'). For that, you must use Promise.
So your createObject function must return a new Promise object, or must be declared as an async function. In your case, since the request function use a callback pattern, you have to use a Promise object because it will provide you a callback that must be called when your Promise resolve.
function createObject() {
return new Promise((resolve, reject) => {
try {
console.log("Processing POST Loan.");
var data = {
"value1" : 1288,
"value2" : [{
"value3" : 3833,
"value4": [{
"value5": new Date()
}]
}]
}
var auth = Buffer.from("login:pass").toString('base64')
const res = request("http://url.com/resource", {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Authorization': "Basic "+auth
},
body: JSON.stringify(data)
}, function(error, response, body){
if(error) reject(error);
resolve({ response, body });
});
}
catch(err) {
reject(err);//the promise is rejected
}
});
}
async function uploadReport() {
console.log('cerate object')
const res = await createObject();
//in res you get 'response' and 'body' where you have the result of your API.
//it's up to you to adapt this to what you want
console.log(res);
}
uploadReport()

My asynchronous javascript gets executed in the middle of the other function

Im trying to execute a function after the other one in Vue.js. I've already tried async/await, callback functions, .then, but it somehow doesnt want to load one after the other. What is a possible solution?
auth_mixin.js:
async auth () {
console.log("authban")
var token = this.getCookie("token")
var jsonData = {}
jsonData["token"] = token
console.log(jsonData)
var bodyFormData = new FormData();
bodyFormData.append('data', JSON.stringify(jsonData));
axios({
method: 'post',
url: 'backend/index.php?action=checkAuth',
data: bodyFormData,
headers: {'Content-Type': 'multipart/form-data'}
})
.then(function (response) {
console.log(response);
if(response.data.status==="OK"){
console.log("ok")
return true;
}else{
console.log("nem ok")
return false;
}
})
.catch(function (response) {
console.log(response);
return false;
});
}
Navbar.vue:
created () {
var result=false
this.auth().then(this.checkIfLoggedIn(result))
},
methods: {
checkIfLoggedIn (isLoggedIn) {
console.log("na ez lesz az erdekes "+isLoggedIn)
if(isLoggedIn === true){
console.log("true")
document.getElementById("logged_out").style.display="none";
document.getElementById("logged_in").style.display="block";
}else{
console.log("fail");
}
}
}
this.auth().then(this.checkIfLoggedIn(result))
You have two problems.
First: this.checkIfLoggedIn(result) calls checkIfLoggedIn immediately. You need to pass a function to then.
this.auth().then(() => this.checkIfLoggedIn(result))
Second: With that change, you call checkIfLoggedIn when auth resolves.
So when does auth resolve? Well, it is defined with the async keyword, so it resolves when it returns (unless it returns a promise, in which case it adopts that promise instead).
So what does it return? It has no return statement, so it returns undefined when it gets to the end … which is immediately after the call to axios (since you aren't awaiting that).
If you returned the return value of axios(...).etc then it wouldn't resolve until that promise resolved.
(Aside: You're using async, you should probably refactor to use await, try {} catch() {} instead of .then() and .catch()).

Javascript: Promise returning instantly, rather than waiting for asynchronous process to finish

Essentially when i call my function getToken() it should return the bearer + token from the api.
The problem I have is that due to the asynchronous process that happens, the data is not returned instantly; so in reading the following resource:
How do I return the response from an asynchronous call?
My understanding is that I need to return my response in the form of a promise, and set a timeout to ensure that the return accounts for the time it takes for the server to send back my request in the form of a response.
var request = require('request-promise');
var time = require('timers');
class Auth {
getToken() {
let options = {
method: 'POST',
uri: 'https://example.com/service/ep',
body: {
username: 'someUser',
password: 'somePass'
},
json: true
}
request(options)
.then(function (body) {
// console.log(body)
return new Promise((resolve) => {
time.setTimeout(() => {
resolve(body)
},3000)
});
})
.catch(function (err) {
return err
});
}
}
module.exports = new Auth
Unfortunately when i run my program in the node repel, it returns nothing and it does not appear to wait; of course when i log my response 'console.log(body)', it appears meaning there must be something wrong with how i'm returning my promise; i'm quite new to the likes of promises.
Could use with a second pair of eyes.
My understanding is that I need to return my response in the form of a promise, and set a timeout to ensure that the return accounts for the time it takes for the server to send back my request in the form of a response.
No. You need to return a promise (request already gives you one) and then the code you return the promise to needs to expect a promise (and call then() on it to get the data).
You don't need any time delays.
var request = require('request-promise');
var time = require('timers');
class Auth {
getToken() {
let options = {
method: 'POST',
uri: 'https://example.com/service/ep',
body: {
username: 'someUser',
password: 'somePass'
},
json: true
}
return request(options);
}
}
module.exports = new Auth
const auth = require("Auth");
auth.getToken().then(function (data) {
console.log(data);
});

Logging value from promise .then() shows data but when returning it is undefined [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
So I have a function that uses the refresh token I have to get a new access token and I want to use this function before every call that requires an access token.
The first function refreshAccessToken() makes the request and returns the response including the body that contains the new access token. Now I thought this was enough but I was getting undefined followed by the actual data and doing some digging I found this question:
Promise returns undefined
which led me to returning the value from this function so the promise resolves fully and using it in another, returnAccessToken().
returnAccessToken() is supposed to take the resolved promise value and return the access token but it behaves unexpectedly. The console.log line works like a charm and it logs the correct value everytime but when I return the token and try to use it in the function below it, it is undefined again.
api.js
"use strict"
const request = require("request-promise-native");
refreshAccessToken: async function (credentialsObject) {
const options = {
method: "POST",
uri: <refresh token uri>,
resolveWithFullResponse: true,
json: true
};
return await request(options);
},
returnAccessToken: function (auth) {
this.refreshAccessToken(auth)
.then(function (result) {
// This logs the result correctly
console.log(result.body);
return result.body;
}, function (err) {
console.log(err);
});
},
actionRequiringAccessToken: function (auth) {
let tokens = this.returnAccessToken(auth);
// This returns undefined
console.log(tokens);
}
index.js
Also yes I realize that logging here does nothing as I don't currently return a value I just include it because this is how actionThatRequiresAccessToken() is run in my setup.
"use strict"
const api = require("api");
let auth = {
// Credentials
};
api.actionRequiringAccessToken(auth)
.then(function (data)) {
console.log(data);
}, function (err) {
console.log(err);
}
Just add return in returnAccessToken method.. you are not returning anything
returnAccessToken: function (auth) {
return this.refreshAccessToken(auth)
return result.body;
That returns the data into the .then chain. So actually your method doesnt return anything. Might add a return here:
returnAccessToken: function (auth) {
return this.refreshAccessToken(auth) /*...*0
}
I would suggest make actionRequiringAccessToken async and drop returnAccessToken
actionRequiringAccessToken: async function (auth) {
let response = await this.returnAccessToken(auth);
let tokens = response.body //parse the response... whatever returnAccessToken does
console.log(tokens);
}

get callback arguments from sinon.spy inside promise javascript

I'm running a test using mocha and sinon to get a callback value from inside a promise scope of HTTP-request and it doesn't work due to the async nature of promises. It's because by the time sinon.spy checks on callback, It would have been vanished already and become empty or undefined. Here's the testing code:
it('should issue GET /messages ', function() {
server.respondWith('GET', `${apiUrl}/messages?counter=0`, JSON.stringify([]));
let callback = sinon.spy();
Babble.getMessages(0, callback);
server.respond();
sinon.assert.calledWith(callback, []);
});
and the promise:
function requestPoll(props) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(props.method, props.action);
xhr.timeout = 500; // time in milliseconds
if (props.method === 'post' ) {
xhr.setRequestHeader('Content-Type', 'application/json');
}
xhr.addEventListener('load', function(e) {
resolve(e.target.responseText);
});
xhr.send(JSON.stringify(props.data));
});
}
and the call which I'm trying to get callback from on sinon.spy
getMessages: function(counter, callback){
requestPoll({
method: "GET",
action: "http://localhost:9090/messages?counter="+counter
}).then(function(result){
callback(result);
});
}
sinon.spy says it didn't have any arguments (due to async functionality). I tried to look for a way to get result outside the scope and put it on callback.yet I found out it was impossible. also tried resolve and promise return but didn't succeed.
How can I make this unit test pass?
Edit:
this is my attempt:
getMessages: function(counter, callback){
var res;
res = httpRequestAsync("GET",'',"http://localhost:9097/messages?counter=",counter);
console.log(res);
if(res!="")
callback( JSON.parse(res) );
}
I put the request in a separate function:
function httpRequestAsync(method,data,theUrl,counter)
{
return requestPoll({
method: method,
action: theUrl+counter,
data: data
}).then(JSON.parse);
}
It returned res as the promise and inside its prototype there's the promised value I need.
How can I access that promised value over there?
I recommend you not to mix promises and callbacks. If you already have promise based function stick with it
First make getMessages not to break promise chaing. Make it return a Promise
getMessages: function(counter) {
return requestPoll({
method: "GET",
action: "http://localhost:9090/messages?counter=" + counter
}).then(JSON.parse)
}
Then use this promise in your test
it('should issue GET /messages ', function() {
server.respondWith('GET', `${apiUrl}/messages?counter=0`, JSON.stringify([{testdata}]));
const gettingMessages = Babble.getMessages(0);
server.respond();
// return a promise so testing framework knows the test is async
return gettingMessages.then(function(messages) {
// make assertion messages is actually testdata
})
})

Categories

Resources