Why is this output reached? - javascript

Can anyone tell me why this code outputs the following? I am completely lost on async functions and close to just giving up.
The first await does what I expect and waits 1 second before executing. However, somehow 301 is outputted before the then before it is executed which seems to completely defy the literal definition of then. Done is outputted then somehow it goes back and executes the second then statement.
async function test() {
const promise1 = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
console.log('First await executed')
}, 1000)
}).then(() => {
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
console.log("This was executed")
}, 1000)
})
}).then(() => Promise.resolve(301));
console.log(promise1)
await setTimeout(() => console.log(1000), 1000)
console.log("Done");
}
test()

Related

Why does the for of loop inside of an async function break instead of awaiting?

Edit 2:
So I changed things to use setTimeOut instead and that did the trick. See the accepted answer for what was causing the actual error.
The code below works fine.
async function getSlices() {
const imgBuffs = await sliceImg('./example.png', 128, 128)
let saveInd = 0
for (const buff of imgBuffs) {
const asciified = await asciify(buff, options)
console.log(asciified)
await setTimeout(() => {}, 1000)
await execShellCommand(`clear | import -window root -crop 904x904+0+66 ${saveInd}.png`).then((res, rej) => saveInd++)
await setTimeout(() => {}, 1000)
}
}
Edit: Added missing important code
The following function slices images and turns them into ascii (this works). Then, the function is supposed to console.log the data, wait a little, take a screenshot, wait again and then move on to the next saved buffer. Without delays, the function works, but it takes badly timed screenshots. With the await delays, the function stops at the first delay.
async function getSlices() {
const imgBuffs = await sliceImg('./example.png', 128, 128)
for (const buff of imgBuffs) {
console.log('Starting to wait for asciified')
const asciified = await asciify(buff, options)
console.log(asciified)
console.log('Ascifiied done, waiting for first delay')
// the function stops here...
await delay(100)
console.log('executing the command')
await execShellCommand('clear | import -window root -crop 904x904+0+66 Image2.png').then((res, rej) => console.log('Shot saved'))
await delay(100)
console.log('all done')
}
async function execShellCommand(cmd) {
const exec = require('child_process').exec;
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.log(error);
}
console.log('here')
resolve(stdout ? stdout : stderr);
});
});
}
const delay = ms => new Promise(res => setTimeout(res, ms));
You probably get
Cannot access 'delay' before initialization
You don't have any catch or try..catch blocks so you don't see the error
Invisible error:
async function getSlices() {
console.log('Starting to wait for asciified')
await delay(100)
console.log('all done')
}
getSlices()
const delay = ms => new Promise(res => setTimeout(res, ms));
Visible with catch:
async function getSlices() {
console.log('Starting to wait for asciified')
await delay(100)
console.log('all done')
}
getSlices().catch(console.error)
const delay = ms => new Promise(res => setTimeout(res, ms));

Cannot control the order of asynchronous tasks using promise

I am facing an issue while using promise to control async tasks in JavaScript. In the following code, I wanted to output 'first' before 'second'. I used promise then block, but it didn't work as I wanted.
I used setTimeout to create different time delay, so that I can control async tasks order no matter what. Can anyone please help me understand why the code is not giving the output I wanted?
Here is the code:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
first.then(second);
I don't believe that your code sample reflects your real situation, so I think it's not useful to solve the issue in your code sample.
Here is what I think you have:
// a task that returns a promise and takes some amount of time
const task = (name) => new Promise(resolve => setTimeout(() => resolve(name), Math.random() * 1000));
// a function using the task result
const taskDone = (name) => console.log(name + ' done');
// two instances of that task, finishing in unpredictable order
var action1 = task('task 1').then(taskDone);
var action2 = task('task 2').then(taskDone);
Run the snippet a few times to see that the result order changes. All you want a way to ensure that 'task 1 done' is always printed before 'task 2 done', even if task 2 finishes earlier.
The way to do this is to use Promise.all().
const task = (name) => new Promise(resolve => setTimeout(() => resolve(name), Math.random() * 1000));
const taskDone = (name) => console.log(name + ' done');
// set up tasks
var allTasks = [task('task 1'), task('task 2')];
// wait for results and evaluate
Promise.all(allTasks).then(allResults => allResults.forEach(taskDone));
allResults will be in the same order as allTasks, so 'task 1 done' will now always be printed before 'task 2 done'.
If you only have two tasks, you can be more explicit:
Promise.all([
task('task 1'),
task('task 2')
]).then(allResults => {
taskDone(allResults[0]);
taskDone(allResults[1]);
});
Wrap it to a function and create a closure and it will be called when you call it right the way.
let first = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
let second = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
first().then(second);
The first problem is that your promise constructor executor functions call console.log() before the promises are even fulfilled. Instead, you should wait to console.log() the values that promises are fulfilled with:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('first');
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('second');
}, 3);
});
first.then((value1) => {
console.log(value1);
});
second.then((value2) => {
console.log(value2);
});
Now for the matter of sequencing the output, you can achieve this by awaiting the fulfilled value of second only after awaiting the fulfilled value of first, rather than awaiting both of them at the same time:
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('first');
}, 30);
});
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('second');
}, 3);
});
first.then((value1) => {
console.log(value1);
return second;
}).then((value2) => {
console.log(value2);
});
If you start two promises parallelly which are resolved by setTimeout then there is no way you can control your logs order.
You need to establish some order dependency between the two to resolve them in order.
One way could be as follows:-
let first = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('first'));
}, 30);
});
first.then(() => {
let second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log('second'));
}, 3);
});
return second;
})

How to get all promises in map with timeout inside

I am trying to get all the results from a map with time out.
I’ve tried to use promise.all() But it didn’t succeed because of the setTimeout function.
I will be happy if someone can look oh my code and suggest how to do it right.
Thank you very much.
new Promise(async (resolve, reject) => {
Promise.all(
items.map(async (item, i) => {
await setTimeout(async () => {
return await SendMail(item);
}, 5000 * i);
})
).then((mailsRes) => {
resolve(mailsRes);
});
});
Simply loop through your items and sleep for x seconds (5 in this example) after sending each email.
const sleep = (milliSeconds) => {
return new Promise((resolve, _reject) => {
setTimeout(() => {
resolve()
}, milliSeconds)
})
}
const sendEmails = async (items) => {
for (let i = 0; i < items.length; i++) {
const currentItem = items[i];
await SendMail(currentItem);
await sleep(5000)
}
}
as you see sendEmails is an async function then you can call it by:
await sendEmails(items)
Not sure what you are trying to achieve but you probably need this-
async function timeout(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
});
}
new Promise( async (resolve, reject) => {
Promise.all(items.map( async (item, i)=>{
await timeout(5000 * i).then(() => {
return await SendMail(item);
});
}))
.then(mailsRes => {
resolve(mailsRes)
})
});
The problem is that setTimeout is resolved immediately and you get a timeout canceller in the next callback.
If I understand you correctly, that might do the trick:
function delayedSendMail(item, i) {
return new Promise(resolve => setTimeout(() => resolve(SendMail(item)), 5000 * i));
}
Promise.all(items.map((item, i) => delayedSendMail(item, i)))
.then(mailResults => {
// handle results
});

How to set a time limit to a method in NodeJs?

I have a use case, where I am doing an external API call from my code,
The response of the external API is required by my code further on
I am bumping into a scenario, where the external API call at times takes far too long to return a response,
casing my code to break, being a serverless function
So I want to set a time limit to the external API call,
Where if I don't get any response from it within 3 secs, I wish the code to gracefully stop the further process
Following is a pseudo-code of what I am trying to do, but couldn't figure out the logic -
let test = async () => {
let externalCallResponse = '';
await setTimeout(function(){
//this call sometimes takes for ever to respond, but I want to limit just 3secs to it
externalCallResponse = await externalCall();
}, 3000);
if(externalCallResponse != ''){
return true;
}
else{
return false;
}
}
test();
Reference -
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property
I'm using AWS SSM's getParameters method
You cannot await setTimeout as it doesn't returns a Promise.
You could implement a function that returns a Promise which is fulfilled after 3 seconds.
function timeout(seconds) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1000)
});
}
You can await the above function in your code passing the number of seconds you want to wait for
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await externalCall();
}, 0);
await timeout(3); // wait for 3 seconds
if(externalCallResponse != '') return true;
else return false;
}
Following code snippet demonstrates the usage of timeout function written above. It mocks a api request that returns a response after 4 seconds.
function timeout(seconds) {
return new Promise(resolve => {
setTimeout(resolve, seconds * 1000);
});
}
function apiRequest() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 4000);
});
}
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await apiRequest();
}, 0);
await timeout(3); // wait for 3 seconds
if (externalCallResponse != '') return true;
else return false;
};
test()
.then(res => console.log(res))
.catch(err => console.log(err.message));
you can use something like this, I created a function that return a promise then I used this promise.
let test = async () => {
return promiseTimeout()
}
const promiseTimeout = () => {
return new Promise(async (resolve, reject) => {
setTimeout(function () {
let externalCallResponse=""
externalCallResponse = await externalCall();
if (externalCallResponse != '') {
return resolve(true);
}
else {
return resolve(false);
}
}, 3000);
})
}
test().then(result=>{
console.log(result);
});
You could do something like this:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
timeout(() => doStuff(), 3000)
.then(() => console.log('worked'))
.catch(() => console.log('timed out'));
Tests:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
const doStuffShort = async () => { // Runs for 1 second
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
const doStuffLong = async () => { // Runs for 5 seconds
return new Promise((resolve) => setTimeout(() => resolve(), 5000));
}
timeout(() => doStuffShort(), 3000)
.then(() => console.log('1 worked'))
.catch(() => console.log('1 timed out'));
timeout(() => doStuffLong(), 3000)
.then(() => console.log('2 worked'))
.catch(() => console.log('2 timed out'));

Unable to retrieve data from a promise

I am unable to retrieve data from a promise using then(). Where am I going wrong?
async function A(){
await new Promise((resolve, reject) => setTimeout(()=>{},1000));
return 45;
}
A().then(data => console.log(data))
I'm running this code with nodejs.
I expect the output to print 45. But the program just executes for 1 second and doesn't print anything.
If I remove the timeout statement, I am able to print 45.
Where am I going wrong?
You need to resolve your promise and then return can run.
async function A() {
await new Promise((resolve, reject) => setTimeout(() => resolve(), 1000));
return 45;
}
A().then(data => console.log(data))
You could also return promise from A function and then use async/await.
function A() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(45), 1000)
})
}
(async() => {
const res = await A();
console.log(res)
})()
Your function A should return a promise.
function A() {
return new Promise((resolve, reject) => setTimeout(() => resolve('hello'), 1000));
}
A().then(data => console.log(data))
Function A should return a promise and use async/await along with IFI (Immediate Function Invocation method)
function A(){
return new Promise((resolve, reject) => setTimeout(()=>{resolve(100)},1000));
}
(async () => {
var data = await A()
console.log(data)
})();

Categories

Resources