Issue with promises - javascript

I am trying to use promises. Basically puting http connections in one js and calling from another js. But I am not able to do so. What's the mistake here?
http.js
'use strict';
const fetch = require('node-fetch');
module.exports.get = async (url) => {
console.log("inside get method");
const promise = new Promise(function (resolve, reject) {
console.log("inside promise");
fetch(url)
.then(res => {
console.log("inside fetch");
resolve(res.json());
})
.catch(json => reject(Error(json)));
})
return promise;
}
main.js
'use strict';
const http = require('/opt/http.js')
module.exports.httpTest = async (event) => {
let url = 'http://www.someurl.com/';
console.log("calling get method");
http.get(url).then(
function (data) {
console.log("inside http then")
console.log(data);
}).catch(function (data) {
console.log(data);
});
console.log("exited get method");
}
As you can see in http.js I have written a wrapper for GET request which I am trying to use in main.js.
When I execute main.js, nothing fails, but not get displayed on console. What I am doing wrong here?
UPDATE
I have added console logs everywhere... and when I call httpTest from anywhere, here is what I am getting
calling get method
inside get method
inside promise
exited get method
basically it's not going inside fetch

Don’t create a useless extra promise.
// this is a code smell
const promise = new Promise(function (resolve, reject) {
console.log("inside promise");
fetch(url)
.then(res => {
console.log("inside fetch");
resolve(res.json());
})
.catch(json => reject(Error(json)));
})
return promise;
Just return fetch(url); which already returns a promise. Your wrapper promise adds nothing.
Second, your exited get method is going to run outside the promise chain. If you want that to run after get finishes you need to await the http.get call inside HttpTest.

Related

Promises jumping too fast to then() (vanilla JS)

I have a problem with promises. The point is that the one function isn't completed and the executing code is jumping to then method.
const load = (function() {
const site = function(url, parent) {
return fetch(url)
.then(response => {
return response.text()
})
.then(data => {
parent.innerHTML = data;
})
};
return {
site: site,
};
})();
function mainApp() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(document.querySelector('.content'));
const welcome = document.createElement('div');
const content = document.querySelector('.content');
welcome.textContent = `Welcome, ${user.displayName}`;
content.appendChild(welcome);
} else {
}
});
}
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
//this function isn't completed and executing code is jumping to then
})
}
promise().then(() => {
console.log('then');
mainApp(); //this function is called before the upper code is completed
});
And because of this bug I can't change the DOM in mainApp function because this function is completed before the load function (which is also changing to DOM by using fetch). My goal is to firstly call and complete load.site() and then mainApp() but I don't know what's happening now and where is the problem.
I assume that you assumed that we assume that you resolved the function like
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
resolve(); // Like this.
})
}
The Problem
When you call promise. It calls load.site and then resolves. So why isn't it giving the expected behavior.
Well, the problem is that load.site is a synchronous function, so it does not wait for the fetch call and returns which resolves promise before fetch is resolved. So, the code in promise.then() runs before the code in fetch.then()
The Solution
Make load.site an asynchronous function so that it returns a promise that can be awaited. i.e.
const site = async function (url) {
return fetch('a.js')
.then(response =>{
return response.text()
})
.then(data =>{
console.log("Loaded");
})
};
Then make the promise's executor async so that you await load.site. i.e.
function promise() {
return new Promise(async (resolve, rejected) => {
await load.site('pages/main/main.html'); // This line does the magic
resolve();
});
};
This will make sure that your promise resolves after fetch has resolved. So that you can get the expected behavior.
Hope it helps. Keep on coding

Wait for response from request before returning

I am trying to create a function with a GET request that returns a portion of the data from the GET request. However, it keeps returning before the data is retrieved, so I keep getting "undefined". How can I set this up so it actually waits for the data to be set before returning?
let getInfo = async () => {
const request = net.request({
url: URL
})
return new Promise((resolve, reject) => { // Promise being here DOES work
request.on('response', (response) => {
response.on('data', (chunk) => {
//return new Promise((resolve, reject) => { //Promise being here does NOT work
let body = JSON.parse(chunk)
let info = body.data
if (info){
resolve(info);
}
reject();
//})
});
});
request.write('')
request.end()
}).then(data => {
console.log("From then: "+data)
return data
})
}
getInfo().then(data => {
console.log("From outside: "+data)
})
Edit: This is the updated version that still does not work. I am trying to use the native electron method and I don't see why this doesn't work. The "From then:" part displays the info correctly. But when run "From outside:" it prints undefined. Does the issue have anything to do with the response.on being nested inside the request.on?
Solution: As #NidhinDavid showed in his answer, the issue was that the promise was inside the 'response' listener. Moving the 'GET' request from start to finish inside the Promise fixed it to giving the correct output. I have updated my code to reflect that for future individuals.
let getInfo = () => {
let info;
const request = net.request({
url: URL
})
return new Promise((resolve, reject) => {
request.on('response', (response) => {
response.on('data', (chunk) => {
request.write('')
request.end()
let body = JSON.parse(chunk)
info = body.data
if (info) {
resolve(info)
} else {
reject('Something went wrong');
}
});
});
})
}
getInfo()
.then(data => {
// this will be your info object
console.log(data)
})
.catch(err => {
// this will log 'Something went wrong' in case of any error
console.log(err)
})
You need to return inside your, on type event handler. Read more about asynchronous code and synchronous code here
I couldn't find the net module and the one which is included with Nodejs do not have request method. So to get the similar concept of event emiters and promise I am using http module and doing a http request to fetch json and parse it
'use strict'
var https = require('https');
const getInfo = async () => {
// create a new promise chain
// remember it is a chain, if one return is omitted
// then the chain is broken
return new Promise((resolve, reject) => {
var options = {
host: 'support.oneskyapp.com',
path: '/hc/en-us/article_attachments/202761727/example_2.json'
};
// start the request
https.request(options, function (response) {
var str = '';
// data arrives in chunks
// chunks needs to be stitched together before parsing
response.on('data', function (chunk) {
str += chunk;
});
// response body obtained
// resolve (aka return) the result
// or parse it, or do whatever you want with it
response.on('end', function () {
resolve(str)
});
// errors are another event
// listen for errors and reject when they are encountered
response.on('error', function (err) {
reject(err)
})
}).end()
})
}
//*********************************************
// using async await
//*********************************************
// if this is the entry point into app
// then top-level async approach required
(async ()=>{
try{
let data = await getInfo()
console.log("From ASYNC AWAIT ")
console.log(JSON.stringify(JSON.parse(data)))
}
catch (err) {
console.log("operation failed, error: ", err)
}
})();
//************************************************
// using promise chains
//************************************************
getInfo()
.then((data)=>{
console.log("FROM PROMISE CHAIN ")
console.log(JSON.stringify(JSON.parse(data)))
})
.catch((err)=>{
console.log("operation failed, error: ", err)
})
Tyr this, it might works for you,
let info;
const getInfo = async (_url)=>{
const response = await fetch(_url);
const data = await response.json();
info = data;
} ;
const url = "some url";
getInfo(url);
console.log(info);
Async function always returns a promise, so either consume that promise or internally await the data and assign it to some variable.
Check for the valid data required in info by logging it to the console.

How to return Papa-parsed CSV via promise/async-await

Can someone help me understand why this returns a pending promise, rather than the data?
async function toJson (filepath) {
const file = fs.createReadStream(filepath)
let json = new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
complete (results, file) {
resolve(results)
},
error (err, file) {
reject(err)
}
})
})
let result = await json
return result.data
}
If I change the return result.data line to console.log(result.data), it logs the data array to the console, as expected. Why won't it simply return that array?!?!
As Roamer-1888 added in the comments, async functions always return a Promise, even if you await inside it and then return the data it will return as a Promise.
In the function's caller, you will have to await the Promise or use .then() on it in order to access the delivered data.
The toJson function could be better written to just return a Promise like this
function toJson (filepath) {
const file = fs.createReadStream(filepath)
return new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
complete (results, file) {
resolve(results.data)
},
error (err, file) {
reject(err)
}
})
})
}
Now when you call toJson(), you can use either await if you are inside of an async function or chain .then() on the returned Promise to access the data.
async function main() {
try {
const data = await toJson(filepath)
// do something with the data...
} catch (err) {
console.error('Could not parse json', err)
}
}
Or with .then()
toJson('path')
.then(console.log)
.catch(console.log)
You will be able to catch errors from the underlaying FileReader (thanks to calling reject inside the error function). Keep in mind that by calling resolve with results.data you put aside results.errors and results.meta which contain useful information about the read csv.

JavaScript | Access the object of a Promise from another Promise

In my AngularJS Application, I want to access the return value of a Promise, which I access from a service outside of my controller and import it there. This Promise, return an object. I want to access that objects and properties inside it.
I created the service to get that endpoint. Look below:
export const getEndpoints = () => {
const options = {
method: httpMethod.GET,
url: endpoint.ENVIRONMENT,
};
return Instance(options);
};
The above service in return reads an endpoint which I provide and uses axios on the background. This part is working just fine.
Then imported it, on my angular Controller:
import { getEndpoints } from './config/service';
Finally I created this function:
$scope.isItAvailable = false; // I will use this later to check the actual value. It is not important in the scope of the question..
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints)
console.log(getEndpoints)
})
}
// And in my main function I am just calling the above
const mainFn = () => {
checkIfItIsAvailable()
// Along with a few others..
}
Actual Results
Now, in my console, I get the functioncheckIfItAvailable printed out.
Expected Results
I instead want to print to the console, the actual value that is being returned by the original promise, the object, and its properties.
Probably You need to call that function instead of just passing it as a parameter.
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints()) // here
console.log(getEndpoints())
})
}
Then to get that resolved later in your main function, or wherever - just use then:
const mainFn = () => {
checkIfItIsAvailable().then((result) => {
// do what you need with result here
// $scope.isItAvailable = result probably like this
});
}
Please comment if you need another result. I see at least this issue at the moment.
Also, here is a snipper, illustrating that you need to call it instead of just passing.
// here is an example function which just return some string
function getSomething() {
return 'something'; // it could be a promise also
}
// here is example without calling functions, but just passing:
const promise = new Promise((resolve, reject) => {
console.log('NO CALL: ', getSomething);
});
// here is example with calling, so value is resolved
const promise2 = new Promise((resolve, reject) => {
console.log('CALLED: ', getSomething());
});
Here, getEndpoints is an asynchronous function which returns a Promise, and the way to get a return value from promise is to use then callback. You can do it like this:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
getEndpoints().then(resultOfEndPoint => {
console.log(resultOfEndPoint);
resolve(resultOfEndPoint);
});
})
}
It's possible to access the resolved result of getEndpoints in checkIfItIsAvailable calling getEndpoints() and using then() function:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
// call getEndpoints
getEndpoints()
// call then to get a result from getEndpoints
.then(res => {
console.log(res);
// checkIfItIsAvailable will be resolved with
// the result of getEndpoints
resolve(res);
});
});
}

Vue exports.function syntax

i have a function like this in a separate file.
exports.getScore = (storeId) => {
var getScore = new Promise(function (resolve, reject) {
let data = this.getScore('day', storeId)
data.then(function (result) {
resolve(result)
})
})
let result
await getScore.then(function (data) {
result = data
})
return result
}
Can anyone help me with the syntax so i can make async runs, and then execute my await call?
Thanks in advance.
For your question you just need to place an async before your function
exports.getScore = async (storeId) => { /* snip */ }
But actually there are some problem in your code
First, you can pass a promise in Promise executor's resolve
new Promise(resolve => {
// This will work
resolve(anotherPromise)
})
However, if you already have a promise you can just return it directly
If you want to make sure it's a native Promise or you are not sure that it's a Promise or not.
Wrap it in Promise.resolve
Promise.resolve(anotherPromiseOrValue)
So your code can change into:
exports.getScore = (storeId) => this.getScore('day', storeId)
And it also equal:
exports.getScore = this.getScore.bind(this, 'day')
But there is another problem: what is the this here ?
If you extract this function from Vue methods, then the this probably is a Vue instance.
Then I afraid that the above code wont work as you expected.
So I recommend that you just use getScore in your component's lifecycle hook, like mounted
For example:
mounted () {
this.getScore('day', this.storeId).then(score => {
this.score = score
})
}
Or with async/await
async mounted () {
this.score = await this.getScore('day', this.storeId)
}

Categories

Resources