Cannot control the order of asynchronous tasks using promise - javascript

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;
})

Related

Promise is not working, resolve is not giving the answer

I am doing tasks with chatGPT and I've got this task
Create a promise that resolves to a string "Hello World" after 2 seconds.
Its answer is:
const greeting = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello World");
}, 2000);
});
However, its not working for me. What works for me is:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() =>{
resolve();
}, 2000)
})
myPromise.then(() => console.log('Hello World'))
Why I can't get answer in resolve?

Why is this output reached?

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()

Leave async timer

First of all I'm sorry I'm a very beginner in JS. The following code stucks at the third line. In the background_mine method. I don't have access to this method, so how can I reset the code after 2 minutes stucking in this method
Mining = async () => {
console.log(`## rebalance: ${await getBalance(account, wax.api.rpc)}`);
let mine_work = await background_mine(account)
}
You may need to do a Promise.race
Example working properly:
const background_mine = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_mine'), 500);
});
const limitChecker = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_failed'), 1000);
});
const result = await Promise.race([background_mine, limitChecker])
.catch((error) => {
console.log(`This timed out`);
});
console.log(result); //background_mine
Example having a timeout:
const background_mine = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_mine'), 500);
});
const limitChecker = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_failed'), 1000);
});
const result = await Promise.race([background_mine, limitChecker])
.catch((error) => {
console.log(`This timed out`);
});
console.log(result); //undefined
If you check, it all depends on wether background_mine functions is below or above the limitChecker timeout value.
In order to implement a timeout, you can use Promise.race like this:
const background_mine = account => new Promise(() => {});
const promisifiedTimeout = new Promise((resolve, reject) => setTimeout(() => reject('Timed out'), 5000));
(async () => {
const account = {};
try {
const result = await Promise.race([background_mine(account), promisifiedTimeout]);
}
catch(e) {
console.log(e);
}
})();

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
});

Promise.all is not waiting for all promises to get resolved

Promise.all is not waiting for all promises to get resolved.In Below code I am trying to replicate a scenarios where depending on some service (two services) response I would be setting the array and then when all service call is done, process.all will give the captrued value. However this does not work.
let errorPromises = [];
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
}, 2000);
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
}, 1000);
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
it should print "All done [1000,3000]" but it prints "All done []"
Please help.
This happens because you are creating promises after the timeout. You need to wrap the timeout in Promise instead
let errorPromises = [];
errorPromises.push(new Promise((resolve, reject) => {
setTimeout(() => resolve(1000), 2000);
}));
// or a one-liner
// errorPromises.push(new Promise(resolve => setTimeout(() => resolve(1000), 2000)));
/// repeat with all others...
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
This happens because you create the promise, before your error promises are in the array. It will take 1 and 2 seconds for the promises to be pushed in the array with timeout, so you get what you want if you wait that the array contains something, for example if you set timeout for the promise too, which should happen AFTER the promises are pushed in to the array.
let errorPromises = [];
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
}, 2000);
setTimeout(() => {
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
}, 1000);
setTimeout(() => {
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});
}, 3000);
So basically you trigger the console log instantly, and then your array is still empty because of the timeout.
let errorPromises = [];
errorPromises.push(new Promise((resolve, reject) => resolve(1000)));
errorPromises.push(new Promise((resolve, reject) => resolve(3000)));
let promise = Promise.all(errorPromises);
promise.then(data => {
console.log("All done", data);
});

Categories

Resources