Why isn't Await blocking the next line of code? - javascript

I'm using an async function to start a server, check if the url returns 200, and then run my tests, but my checkUrl function doesn't complete before running the next line of code.
I'm using the axios package to ping the url for the status code and I've been trying several variations of async/await and Promise.resolve().
function checkUrl(url) {
console.log(`Checking for ${url}`);
return axios
.get(url)
.then(function(res) {
const message = `${url} is status code: ${res.status}`;
return res;
})
.catch(function(err) {
console.log("Will check again in 5 seconds");
setTimeout(() => {
return checkUrl(url);
}, 5000);
});
}
async function init() {
let val;
console.log("Running tests:::");
// start server in react-integration directory
shell.exec("BROWSER=none yarn start", {
cwd: "sampleIntegration/react-integration",
async: true
});
// check server has started
val = await checkUrl("http://localhost:3000");
console.log(`value from checkUrl promise: ${val}`);
}
I'm expecting the val variable to be the message returned from the Promise.resolve() in my checkUrl function.
val is coming back undefined.

The problem is, the setTimeout in the catch block. This is asynchronous, but the catch block immediately returns. As it does not have anything to return, it returns undefined. To resolve this (and also keep your desired behaviour of waiting) you could do something like this:
function checkUrl(url) {
console.log(`Checking for ${url}`);
return axios.get(url)
.then(res => {
const message = `${url} is status code: ${res.status}`;
return res;
})
.catch(err => {
console.log('Will check again in 5 seconds');
return new Promise((resolve) => {
setTimeout(resolve, 5000);
}).then(() => checkUrl(url));
});
}
This will make a Promise which resolves after 5 seconds and on resolve it calls checkUrl.

Related

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.

resolve and reject issue using node js

Is this possible way to return resolve or reject message from one function to another?
As I am writing to pass resolve message in postman whenever my task is completed or reject message when there is some error
But after after writing return it still not returning the resolve message or reject message inside Postman
any idea how this can be resolve?
async function readFile(filePath) {}
async function getAllFile(filePath) {
const paths = await readFile(filePath);
}
async function filterFiles(filePath) {
const paths = await getAllFile(filePath);
}
function addDocument(childProduct){
return new Promise((resolve, reject) => {
Document.create({
name: childProduct,
},
}).then(function (filePath) {
filterFiles(filePath);
let msg = "Document created Succesfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
});
}
function updateDoc(data){
return new Promise((resolve, reject) => {
Document.update({
name: data.name,
}
where: {
product_id: data,
},
})
}).then(function (childProduct) {
addDocument(childProduct);
let msg = "Updated Successfully";
return resolve(msg);
})
.catch(function (err) {
return reject("Can't be updated please try again :) " + err);
});
}
Product.findOne and Document.findAll return a Promise, so they can be returned and awaited directly.
You can chain await func1(); await func2(); await func3() in one try{} block, and catch any error that happens in one place :
const filterFiles = async filePath => {
const paths = await getAllFiles(filePath);
// .. Do something else here
return paths // This is a Promise because async functions always return a Promise
}
const findOneDoc = name => Product.findOne({ where: { name } }); // This func returns a Promise
const findAllDocs = product_id => Document.findAll({ // This func returns a Promise too
raw: true,
where: { product_id }
});
(async () => {
try {
const childProduct = await findOneDoc("some_name");
console.log("All good until now!");
const filePath = await findAllDocs(childProduct._id);
console.log("Still good");
const filteredFiles = await filterFiles(filePath);
console.log("All went well.");
console.log(filteredFiles);
} catch (err) {
// If any of the functions above fails, the try{} block will break and the error will be caught here.
console.log(`Error!`, err);
}
})();
There are few things I would like to mention.
When you create a promise, it should have resolve() and reject() inside it.
for ex-
function testPromise() {
return new Promise((resolve, reject) => {
// your logic
// The followin if-else is not nessesary, its just for an illustration
if (Success condition met) {
resolve(object you want to return);
}else {
reject(error);
// you can add error message in this error as well
}
});
}
// Calling the method with await
let obj = await testPromise()
// OR call with then, but its better to go with await
testPromise().then((obj)=>{
// Access obj here
})
In the method which you have written, You have applied .then() method to non promise object. You have to complete the promise block first with resolve() and reject() inside it. Then you can return that promise from a function, use it in async function Or apply .then() block on it.
Also you don't need to add return statement to resolve() and reject() statement. The system will take care of it.
You can also use try catch block inside a promise. Its better to write reject() statement in catch block, if anything goes wrong.

Halt Execution of Network Request If It Takes Too Long?

I have some code that basically calls fetch in Javascript. The third party services sometimes take too long to return a response and in an attempt to be more user-friendly, I want to be able to either post a message or stop the connection from being open after N milliseconds.
I had recently come across this post:
Skip the function if executing time too long. JavaScript
But did not have much luck and had issues getting it to work with the below code. I was also hoping that there was a more modern approach to do such a task, maybe using async/await?
module.exports = (url, { ...options } = {}) => {
return fetch(url, {
...options
})
}
You can use a combination of Promise.race and AbortController, here is an example:
function get(url, timeout) {
const controller = new AbortController();
return Promise.race([fetch(url, {
signal: controller.signal
}), new Promise(resolve => {
setTimeout(() => {
resolve("request was not fulfilled in time");
controller.abort();
}, timeout)
})]);
}
(async() => {
const result = await get("https://example.com", 1);
console.log(result);
})();
The native Fetch API doesn't have a timeout built in like something like axios does, but you can always create a wrapper function that wraps the fetch call to implement this.
Here is an example:
const fetchWithTimeout = (timeout, fetchConfig) => {
const FETCH_TIMEOUT = timeout || 5000;
let didTimeOut = false;
return new Promise(function(resolve, reject) {
const timeout = setTimeout(function() {
didTimeOut = true;
reject(new Error('Request timed out'));
}, FETCH_TIMEOUT);
fetch('url', fetchConfig)
.then(function(response) {
// cleanup timeout
clearTimeout(timeout);
if(!didTimeOut) {
// fetch request was good
resolve(response);
}
})
.catch(function(err) {
// Rejection already happened with setTimeout
if(didTimeOut) return;
// Reject with error
reject(err);
});
})
.then(function() {
// Request success and no timeout
})
.catch(function(err) {
//error
});
}
from here https://davidwalsh.name/fetch-timeout

Javascript Promise resolve confusion

private runMiddlewares(route: Route | ExceptionRoute, request: HttpRequest, response: HttpResponse): Promise<any> {
return new Promise((resolve, reject) => {
try {
route.middlewares.forEach(async (middleware: IMiddleware) => {
console.log('begin run middleware');
await middleware.process(request, response);
console.log('resolve run middleware');
console.log(request.body);
});
console.log('resolve all runMiddlewares');
resolve();
} catch (e) {
reject(e);
}
});
}
I have written this function runMiddlewares which should ideally resolve() when all the middleware.process() have resolved. I am using typescript await functionality but it doesn't seem to be working.
I expect something like this to happen inside route.middlewares.forEach(
'begin run middleware'
then awaits resolves
'resolve run middleware'
This continues for all of the middlewares in forEach loop and when the list is all done then and only then 'resolve all runMiddlewares' should be printed and finally, private runMiddlewares( ... ) should resolve.
But instead, forEach is now getting immediately resolved thus preventing all of the middlewares to even complete.
How should this be handled? I thought that await will take care of it inside the forEach loop and only then resolve of runMiddlewares will be called in the end.
What am I missing here?
You can use map to create an array of promises from your middlewares. This array of promises can ben handed to Promise.all which resolves when every single promise of the array has been resolved.
await Promise.all(route.middlewares.map((middleware: IMiddleware) => {
console.log('begin run middleware');
const promise = middleware.process(request, response);
console.log('resolve run middleware');
console.log(request.body);
return promise
});
Or even more compact:
runMiddlewares(...) {
return Promise.all(
route.middlewares.map((middleware: IMiddleware) => {
return middleware.process(request, response))
})
)
}
So, following the recommendation ( https://cn.eslint.org/docs/3.0.0/rules/no-await-in-loop ), I wrote it as follows
private runMiddlewares(route: Route | ExceptionRoute, request: HttpRequest, response: HttpResponse): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
const middlewarePromiseArry: any[] = [];
route.middlewares.forEach((middleware: IMiddleware) => {
console.log('begin run middleware');
middlewarePromiseArry.push(middleware.process(request, response));
// removed the use of await inside of forEach loop following this link: https://cn.eslint.org/docs/3.0.0/rules/no-await-in-loop
// await middleware.process(request, response);
// console.log('resolve run middleware');
// console.log(request.body);
});
await Promise.all(middlewarePromiseArry);
console.log('resolve all runMiddlewares');
resolve();
} catch (e) {
reject(e);
}
});
}
I am happy to accept further answers and recommendations/improvements :)

How to resolve Web3 promises objects? [duplicate]

Im trying to use async await on a function that returns a promise but the out put im getting is Promise { <pending> }. In here im using function called convertFiletoPDF which returns a promise. I need to get the output (the path that i have mention in resolve() ).
When i use it as
convertFiletoPDF(file).then((result) => {
console.log(result);
}).catch((err)=>{
console.log(err);
});
it gives the expected result.Whats wrong with the code below? im quite new to these async await and promises.
function convertFiletoPDF(file) {
return new Promise(function(resolve, reject) {
unoconv.convert(file, "pdf", function(
err,
result
) {
if (err) {
reject(err);
}
let File = file.substring(file.lastIndexOf("/")+1,file.lastIndexOf("."));
// result is returned as a Buffer
fs.writeFile(__dirname+"/files/converted/"+File+".pdf", result, error => {
/* handle error */
if (err) reject(error);
else resolve("./files/converted/"+File+".pdf");
});
});
});
}
async function myfunc(file){
let res = await convertFiletoPDF(file);
return res;
}
let res = myfunc(file);
console.log(res);
The return value of an async function is a promise, so naturally that's what your console.log outputs. You need to either consume the result via await (within another async function) or use then/catch (within another async function).
This is what you're currently doing:
function convertFiletoPDF(file) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, 400, "Done");
});
}
async function myfunc(file){
let res = await convertFiletoPDF(file);
return res;
}
let res = myfunc("some file");
console.log(res);
You need to be doing either this:
function convertFiletoPDF(file) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, 400, "Done");
});
}
async function myfunc(file){
let res = await convertFiletoPDF(file);
return res;
}
(async() => {
try {
let res = await myfunc("some file");
console.log(res);
} catch (e) {
// Deal with the fact there was an error
}
})();
or with then and catch:
function convertFiletoPDF(file) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, 400, "Done");
});
}
async function myfunc(file){
let res = await convertFiletoPDF(file);
return res;
}
myfunc("some file")
.then(res => {
console.log(res);
})
.catch(e => {
// Deal with the fact there was an error
});
convertFiletoPDF()
This function run and returned a Promise. This is fine.
myfunc()
Lets say myfunc takes 10 seconds. Javascript starts to wait newly created thread result from libuv via event loop mechanism. So, Javascript says, "That one is async, I will not wait, when it finishes it will let me know and i will run my then callback and then I will proceed with its output."
Javascript keeps his promise. Tries to run next below lines. myFunch is still working. Output is not ready yet. Returns undefined.
let res = myfunc(file);
console.log(res);
You get undefined.
Someone might find this example from my code useful. You can wrap it in a promise and then resolve the custom promise and then call another promise to confirm the receipt of the original web3 call.
return new Promise((resolve, reject) => {
tokenContract.methods.approve(
exchangeAddress,
BIG_NUMBER_1e50
)
.send({ from })
.once('transactionHash')
.once('receipt', receipt => resolve(receipt))
.on('confirmation')
.on('error', err => reject(err))
.then( receipt => // will be fired once the receipt its mined
console.log(receipt),
);
});

Categories

Resources