NodeJS await continues execution without resolved value - node.js

There are other questions similar to this one but not a single one of them helped me visualize my mistake.
I have this code:
function calc() {
return new Promise(resolve => {
setTimeout(() => {
resolve('block finished');
}, 5000);
});
}
async function asyncBlock() {
let result = await calc();
console.log('Result: ' + result);
return result;
}
app.get('/block', (req, res) => {
let result = asyncBlock();
console.log('Already returned the response without the result.');
res.send(result);
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
The execution continues without the await response, giving me this output:
Example app listening on port 3000
Already returned the response without the result.
Result: block finished
Mozilla documentations states that
If a Promise is passed to an await expression, it waits for the
Promise to be fulfilled and returns the fulfilled value.
Mozilla Doc

Your call to AsyncBlock isn't asynchronous.
Try this:
app.get('/block', async (req, res) => {
let result = await asyncBlock();
console.log('Waited for the result');
res.send(result);
})

Related

for bucle blocking express.js route

A loop stops the execution of a route on Express JS until it finishes, this can generate a timeout in the browser.
In the example it takes approx. 10 seconds to show the website (I need to execute the sleep function) , but I would like this for you to continue running on Background, and the route will be displayed immediately
Any suggestion?
app.get('/', function(req, res) {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let array = [1,2,3,4,5,6,7,8,9]
for (const a of array) {
console.log(a)
await sleep(1000);
}
res.send('hello world');
});
If you want the response send immediately, then put the res.send() BEFORE your loop. You can still run code after you've sent the response - that code just can't be involved in computing what the response will be because it will have already been sent.
app.get('/', function(req, res) {
res.send('hello world');
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let array = [1,2,3,4,5,6,7,8,9]
for (const a of array) {
console.log(a)
await sleep(1000);
}
});
Remove the await keyword in the for loop. The await keywords basically stops the code from executing until the current Promise is resolved, so if you dont await on it, it runs alongside other pieces of code. Your response is returned in less than a second, while the node process resolves the sleep promise in the background
app.get('/', function(req, res) {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let array = [1,2,3,4,5,6,7,8,9]
for (const a of array) {
console.log(a)
// await sleep(1000);
sleep(1000);
}
res.send('hello world');
});

Node JS returns undefined within async json call

I have an asynchronous function that is called when the api is connected to. this should return some json and then it will be displayed on the json response of the page. In the json response I get undefined.
This is the code i am using:
const express = require('express');
const router = express.Router();
const superagent = require('superagent');
function getCyrpto(){
var result;
superagent.get('https://min-api.cryptocompare.com/data/v2/pair/mapping/exchange?e=Kraken')
.query({ api_key: 'xxxxxxxx'})
.end((err, res) => {
if (err) { return console.log(err); }
result = res.body;
});
setTimeout(() => {
console.log(result);
return result;
}, 2000)
}
router.get('/', (req, res, next) => {
crypto=getCyrpto()
setTimeout(()=> {
res.status(200).json({
message: 'geting cyrpto',
apiResponse: crypto
});
}, 2500)
});
The reason it is happeing because your setTimeOut methods runs before your api call get the result and assign it to the result.
This is a common problem most of us face when we start to learn concurrency concept.
For example:
console.log("a");
setTimeOut(()=>console.log("b"),1000);
console.log("c");
Output of above function will
a
c
b
this is happening beacause setTimeout function is a promise which means your nodejs will not wait for it to finish before running the next line, it will just process the setTimeout function in background and when it will finish it will call its callback function given as first parameter in setTimeOut.
Your solution should be
function getCyrpto(){
return new Promise((resolve,reject)=>{
var result;
superagent.get('https://min-api.cryptocompare.com/data/v2/pair/mapping/exchange?e=Kraken')
.query({ api_key: 'xxxxxxxx'})
.end((err, res) => {
if (err) { console.log(err); reject(err); }
result = res.body;
setTimeout(() => {
console.log(result);
resolve(result);
}, 2000)
});
}
router.get('/', (req, res, next) => {
getCyrpto().then(crypto=>{
setTimeout(()=> {
res.status(200).json({
message: 'geting cyrpto',
apiResponse: crypto
},2500);
}).catch(err=>{res.status(400).json(err)})
}

How to detect a alert in puppeteer

How can I detect if after a navigation the page shows an alert with some message.
Can puppeteer detect or identify if the page has shown an alert box.
I tried
page.on('popup', ()=> {
console.log('popup detected');
});
also,
page.on('dialog', ()=> {
console.log('popup detected');
});
As said in the comments: If you register the event handlers (your code) after calling page.goto the event is already triggered before you are listening for the event.
Therefore, make sure to call page.goto after your code.
Here are my two cents :
private async gotoPage(path):Promise<Response|Result> {
return new Promise(async(resolve, reject) => {
await Promise.all([
this.page.on('dialog', async (dialog) => {
await dialog.dismiss().catch(() => {
console.log(dialog.message());
return new Result(TestStatus.FAIL, dialog.message());
});
}),
this.page.goto(`${this.baseURL}${path}`),
this.page.waitForNavigation({ waitUntil: 'load' })]).then(
async () => {
resolve(new Result(TestStatus.PASS, `Loading to path success : ${path}`));
},
async () => {
reject(new Result(TestStatus.FAIL, `Could not GotoPage : ${path}`));
});
});
}

Unit test promise result inside Event Listener in Node

I have the following code that I want to test.
emitter.on("request", function(req, res) {
mock_finder.getMockedResponse().then((mockedResponse) => {
res.end(mockedResponse);
});
});
Then, I have this unit test.
it("should return mocked response", () => {
// given
const mockedResponse = {
success: true
};
mock_finder.getMockedResponse.mockImplementation(() => Promise.resolve(mockedResponse));
const res = {
end: jest.fn()
}
// when
emitter.emit('request', req, res);
// then
expect(res.end).toHaveBeenCalledWith(mockedResponse);
});
This test is not working because res.end(mockedResponse); is executed after the test finishes.
How can I test the promise response after an event is called?
Given there's no real async code going on here, you can verify the result on the next tick:
if('should return mocked response', done => {
...
emitter.emit('request', req, res);
process.nextTick(() => {
expect(res.end).toHaveBeenCalledWith(mockedResponse);
done()
});
})

node-celery asychronise, await client.call() finish it's inner function

I am using node-celery 0.2.8 in my node.js server,and I create, use await on client.on(), hoping the code will console log result first, then log 'finally'. But the code console log 'finally' first, then after go through all the code, console log result. Could anyone help me to let the await work on client.on()? I just hope the code can execute in order, and wait at the asychronise request.
async(ctx) => {
const client = celery.createClient({
CELERY_BROKER_URL: 'amqp://guest:guest#172.**.2.**:5672//',
CELERY_RESULT_BACKEND: 'redis://172.**.2.**:6379/2',
CELERY_ROUTES: {
'street.add_account_multi': {'queue': 'street_default'},
}
});
await client.on('connect', () => {
client.call('street.add_account_multi', [crawlers], function (result) {
console.log(result);
});
});
console.log('finally');
}
Please try to put your operation after 'connect' event into a promise and then await resolve.
let clientConnect = new Promise((resolve, reject) => {
client.on('connect',() => {
client.call('street.add_account_multi', [crawlers], function(result) {
console.log(result);
resolve(result);
});
})
});
await clientConnect;
console.log('finally');

Resources