This might seem a silly question, but I am a newbie in this topic. In the script below i have two promises. By now "secondPromise" executing first, and then executing "firstPromise". Cuz in the "secondPromise" i set less time. But how to execute "firstPromise" first, after finished that, start executing the "secondPromise"?
How to rewrite the script below
(async function()
{
//var final = new Array();
var final;
const firstPromise = new Promise(
function(resolve)
{
let result = 2 + 2;
resolve(result);
setTimeout(() => console.log("please show me first"), 2000);
});
const secondPromise = new Promise(
function(resolve)
{
let result2 = 0;
resolve(result2 + 1);
setTimeout(() => console.log("please show me second"), 1000);
});
var myP = Promise.all([firstPromise, secondPromise]).then((values) => {
return values[0]+values[1];
});
return myP;
})();
(async function()
{
//var final = new Array();
var final;
const firstPromise = new Promise(
function(resolve)
{
let result = 2 + 2;
resolve(result);
setTimeout(() => console.log("please show me first"), 2000);
});
const secondPromise = new Promise(
function(resolve)
{
let result2 = 0;
resolve(result2 + 1);
setTimeout(() => console.log("please show me second"), 1000);
});
var myP = Promise.all([firstPromise, secondPromise]).then((values) => {
return values[0]+values[1];
});
return myP;
})();
Quentin's answer is correct: the function you pass to new Promise happens immediately. However: because you already have this in an async function, you can await Promises within it. This pauses the async function until the Promise resolves, so unlike your function with Promise.all that waits for your explicit new Promise Promises in parallel, my function waits for those Promises serially.
Furthermore, if you want the new Promise constructions you wrote to wait for the action in setTimeout, you need to wait and call the resolve method within the callback that setTimeout calls, not outside them as you have it.
console.log("start");
(async function () {
const firstValue = await new Promise(
// ^^^^^
function (resolve) {
let result = 2 + 2;
setTimeout(() => {
console.log("please show me first");
resolve(result); // Promise resolves after 2000ms
}, 2000);
});
const secondValue = await new Promise(
// ^^^^^
function (resolve) {
let result2 = 0;
setTimeout(() => {
console.log("please show me second");
resolve(result2 + 1);
}, 1000);
});
// These are values, not promises, because you await them.
// However, the async function still returns a Promise, because
// "async" covers the asynchronicity of the Promises you await.
return firstValue + secondValue;
})().then(x => console.log(x)); // or .then(console.log)
You can't execute a promise.
You can execute a function.
If you pass a function to a Promise constructor, then it will be executed (by the Promise constructor) immediately.
There is no way to delay the execution of a function passed to a Promise constructor.
You could wrap your calls to new Promise in functions, and then only call the second function when the first promise is resolved.
(Note, however, that in your examples the calls to setTimeout happen after the resolve function is called).
Related
Here i am trying to wrap my head around promises.Here on first request i fetch a set of links.and on next request i fetch the content of first link.But i want to make a delay before returning next promise object.So i use setTimeout on it. But it gives me the following JSON error (without setTimeout() it works just fine)
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of
the JSON data
i would like to know why it fails?
let globalObj={};
function getLinks(url){
return new Promise(function(resolve,reject){
let http = new XMLHttpRequest();
http.onreadystatechange = function(){
if(http.readyState == 4){
if(http.status == 200){
resolve(http.response);
}else{
reject(new Error());
}
}
}
http.open("GET",url,true);
http.send();
});
}
getLinks('links.txt').then(function(links){
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
}).then(function(topic){
writeToBody(topic);
setTimeout(function(){
return getLinks(globalObj["two"]+".txt"); // without setTimeout it works fine
},1000);
});
To keep the promise chain going, you can't use setTimeout() the way you did because you aren't returning a promise from the .then() handler - you're returning it from the setTimeout() callback which does you no good.
Instead, you can make a simple little delay function like this:
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
And, then use it like this:
getLinks('links.txt').then(function(links){
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
}).then(function(topic){
writeToBody(topic);
// return a promise here that will be chained to prior promise
return delay(1000).then(function() {
return getLinks(globalObj["two"]+".txt");
});
});
Here you're returning a promise from the .then() handler and thus it is chained appropriately.
You can also add a delay method to the Promise object and then directly use a .delay(x) method on your promises like this:
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
Promise.prototype.delay = function(t) {
return this.then(function(v) {
return delay(t, v);
});
}
Promise.resolve("hello").delay(500).then(function(v) {
console.log(v);
});
.then(() => new Promise((resolve) => setTimeout(resolve, 15000)))
UPDATE:
when I need sleep in async function I throw in
await new Promise(resolve => setTimeout(resolve, 1000))
The shorter ES6 version of the answer:
const delay = t => new Promise(resolve => setTimeout(resolve, t));
And then you can do:
delay(3000).then(() => console.log('Hello'));
If you are inside a .then() block and you want to execute a settimeout()
.then(() => {
console.log('wait for 10 seconds . . . . ');
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log('10 seconds Timer expired!!!');
resolve();
}, 10000)
});
})
.then(() => {
console.log('promise resolved!!!');
})
output will as shown below
wait for 10 seconds . . . .
10 seconds Timer expired!!!
promise resolved!!!
Happy Coding!
Since node v15, you can use timers promise API
example from the doc:
import { setTimeout } from 'timers/promises'
const res = await setTimeout(100, 'result')
console.log(res) // Prints 'result'
In node.js you can also do the following:
const { promisify } = require('util')
const delay = promisify(setTimeout)
delay(1000).then(() => console.log('hello'))
For the current LTS its easier and we can use async/await to handle timeouts. Please note that this is the recommended way to use timeout nowadays.
Thenables is not the recommended way.
const { promisify } = require('util')
const sleep = promisify(setTimeout)
async function myFunction() {
await sleep(1e3)
console.log('This will be seen after 1 sec')
await sleep(5e3)
console.log('This will be seen after 5 sec after')
}
const myStuff = new Promise(function (resolve) {
console.log("before timeout");
setTimeout(
function (x) {
console.log("inside the timeout");
resolve(x);
},
3000,
"after timeout"
);
}).then((response) => console.log(response));
My code should wait for 4-4 seconds for both the promise to execute total 8 seconds, but it is finishing in 4 seconds only. Why?
Where I am thinking wrong?
// a promise
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1')}, 4000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2')}, 4000);
});
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1;
let result2 = await promise2;
console.log(result1);
console.log(result2);
}
// calling the async function
asyncFunc();
//expected output
**//wait for 4 seconds first**
Promise resolved1
**//wait for more 4 seconds**
Promise resolved2
//output
//waits for 4 seconds
Promise resolved1
Promise resolved2
new Promise(executor)
executor, A function to be executed by the constructor. It receives two functions as parameters: resolutionFunc and rejectionFunc. Any errors thrown in the executor will cause the promise to be rejected, and the return value will be neglected. The semantics of executor are detailed below.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
// a promise
let promise1 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1')}, 4000);
});
let promise2 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2')}, 4000);
});
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1();
console.log(result1);
let result2 = await promise2();
console.log(result2);
}
// calling the async function
asyncFunc();
The promise 1 & 2 is already running when you declared. If you want result that you expect, you should code as above.
When using async/await, your asynchronous code with begin executing, but its resolution will jump back into the synchronous code only when you use the await keyword. When you have multiple asynchronous functions, they will only execute sequentially when you have synchronous code running in between them because when you invoke the function is when the asynchronous portion of the code begins executing. In this case, the timer starts when you invoke the function, so you need to wait for the first timer to resolve before kicking off the second timer.
See this code snippet and check out the examples in this link to clarify.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
async function sequentialStart() {
console.log('==SEQUENTIAL START==')
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds()
console.log(slow) // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second()
console.log(fast) // 3. this runs 3 seconds after 1.
}
The other issue is that when you declare your functions, you run them immediately and assign their values to variables. With minimum modification to your code, you need to set up your functions like below and only call them once you're ready to start the timer.
// a promise
let promise1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1');
}, 4000);
});
};
let promise2 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2');
}, 4000);
});
};
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1();
console.log(result1);
let result2 = await promise2();
console.log(result2);
}
// calling the async function
asyncFunc();
Simple defenation of assync await
when yo declare async a function. The function will decleared as asyncronasly the default value of function is syncronasly . asyncronas function run block level(line by line) when you add await on a promise(function that return value) because of await compiler firstly resolved the promise and then run to next line of code
Let us suppose that we've got a function that resolves a promise like below:
function timeoutPromise(interval) {
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve("done");
}, interval);
});
};
and let us suppose that we call that function inside an asynchronous function in two different ways;
slow synchornous way:
async function timeTest() {
await timeoutPromise(3000);
await timeoutPromise(3000);
await timeoutPromise(3000);
}
Here we simply await all three timeoutPromise() calls directly. Each subsequent one is forced to wait until the last one finished, this will result in total run time of around 9 seconds.
and fast asynchronous way:
async function timeTest() {
const timeoutPromise1 = timeoutPromise(3000);
const timeoutPromise2 = timeoutPromise(3000);
const timeoutPromise3 = timeoutPromise(3000);
await timeoutPromise1;
await timeoutPromise2;
await timeoutPromise3;
}
Here we store the three Promise objects in variables, which has the effect of setting off their associated processes all running simultaneously. This will result in total run time of around 3 seconds.
But the question is, why storing Promise objects in variables has the effect setting off their associated processs running simultaneously? what happens under the hood?
await foo();
await bar();
will only call bar (and thus create the second promise) after the promise returned by foo is resolved.
var x = foo();
var y = bar();
await x;
calls bar (and thus creating the second promise) before the promise returned by foo is resolved.
That's what makes the promises "concurrent". If you add console.log in various places you will see the difference in execution:
function timeoutPromise(name, interval) {
return new Promise((resolve, reject) => {
console.log(`Promise ${name} created.`);
setTimeout(function(){
console.log(`Promise ${name} resolved.`);
resolve("done");
}, interval);
});
};
async function timeTest1() {
console.log('test 1');
await timeoutPromise(1, 3000);
console.log('between promise 1 and 2');
await timeoutPromise(2, 3000);
}
async function timeTest2() {
console.log('test 2');
const timeoutPromise1 = timeoutPromise(1, 3000);
console.log('between promise 1 and 2');
const timeoutPromise2 = timeoutPromise(2, 3000);
await timeoutPromise1;
console.log('between promise 1 and 2 with await');
await timeoutPromise2;
}
timeTest1().then(timeTest2);
How would you wait for a Promise to resolve/reject, for a maximum execution time ? The code below is obviously wrong, it's just to explain what I'm trying to achieve. I'm clueless.
await doSomething();
if ( executionTime > maxExecutionTime ) {
doSomethingElse();
}
This is not for a bluebird promise.
You can use Promise.race() which will immediately resolve/reject when the first promise in its iterable resolves or rejects. E.g.
const longTask = () => new Promise(resolve =>
setTimeout(() => resolve("Long task complete."), 300))
const timeout = (cb, interval) => () =>
new Promise(resolve => setTimeout(() => cb(resolve), interval))
const onTimeout = timeout(resolve =>
resolve("The 'maybeLongTask' ran too long!"), 200)
Promise.race([longTask, onTimeout].map(f => f())).then(console.log)
The only issue is you can't really cancel the 'longTask' just because of its long execution. In theory, you'd either set some flag (to tell it not to continue onto the next stage of its pipeline), or design your application with the consequences of the promise in mind.
See what happens when you swap the 200 and 300 intervals.
Edit: Per spsaucier's comment, I've delayed the execution of each promise until the Promise.line line.
The code below will give you some idea:
function doSomething(maxExecutionTime) {
return new Promise(resolve => {
setTimeout(() => resolve(true), 2000); // this setTimeout simulates your async action which sould not exced maxExecutionTime
setTimeout(() => resolve(false), maxExecutionTime);
});
}
async function someFunc(maxExecutionTime) {
var exced = await doSomething(maxExecutionTime);
if (exced) {
console.log("Doesn't exced max time");
} else {
console.log("Exced max time");
}
}
someFunc(1000);
someFunc(3000);
In ECMA6 You can do something like this:
let promise = new Promise((resolve, reject) => {
let wait = setTimeout(() => {
clearTimeout(wait);
resolve('Timed out after 200 ms..');
}, 200)
})
As noahnu suggested, you can use Promise.race. You can wrap it in a function that takes a promise.
With some syntax sugar you can use thisOrThat which takes logic, a function that takes 2 functions, first and second. You can apply logic here as to try the first function and when to try the second (in our case if the first doesn't resolve within a certain time then try the second).
thisOrThat then takes an argument first that is a function returning a promise (in our case doSomething.
thisOrThat returns an object that has an or property that takes a function returning a promise. That parameter is called second and is passed to logic as second (in our case it is doSomethingElse).
var timeoutPromise =
time =>
promiseFn =>
Promise.race([
promiseFn(),
new Promise(
(_,r)=>
setTimeout(
_=>r("timed out")
,time
)
)
]);
var thisOrThat =
logic =>
first => ({
or:second=>
logic(first)(second)
});
var within75ms = thisOrThat
(first=>second=>
timeoutPromise(75)(first)
.catch(_=>second())
);
var within25ms = thisOrThat
(first=>second=>
timeoutPromise(25)(first)
.catch(_=>second())
);
var doSomething = () =>
console.log("do something called")||
new Promise(r=>setTimeout(x=>r("something"),50));
var doSomethingElse = () =>
console.log("do something else called") ||
new Promise(r=>setTimeout(x=>r("something else"),50));
async function someFunc() {
const doesNotTimeOut =
await within75ms(doSomething).or(doSomethingElse);
console.log("within 75ms resolved to:",doesNotTimeOut);
const doesTimeOut =
await within25ms(doSomething).or(doSomethingElse)
console.log("within 25ms resolved to:",doesTimeOut);
};
someFunc();
I have used Promise.race
// Try to get config from mongo
async function getProjectConfigThreshold(projectName) {
function onTimeoutResolveDefaultThreshold() {
return new Promise(async (resolve) => {
setTimeout(() => {
resolve(DEFAULT_THRESHOLD);
}, 2000)
});
}
async function getThresholdFromProjectConfig() {
const projectConfig = await getProjectsConfig(projectName);
const threshold = projectConfig.threshold || DEFAULT_THRESHOLD;
return threshold;
}
return await Promise.race([getThresholdFromProjectConfig(), onTimeoutResolveDefaultThreshold()]);
}
Here i am trying to wrap my head around promises.Here on first request i fetch a set of links.and on next request i fetch the content of first link.But i want to make a delay before returning next promise object.So i use setTimeout on it. But it gives me the following JSON error (without setTimeout() it works just fine)
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of
the JSON data
i would like to know why it fails?
let globalObj={};
function getLinks(url){
return new Promise(function(resolve,reject){
let http = new XMLHttpRequest();
http.onreadystatechange = function(){
if(http.readyState == 4){
if(http.status == 200){
resolve(http.response);
}else{
reject(new Error());
}
}
}
http.open("GET",url,true);
http.send();
});
}
getLinks('links.txt').then(function(links){
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
}).then(function(topic){
writeToBody(topic);
setTimeout(function(){
return getLinks(globalObj["two"]+".txt"); // without setTimeout it works fine
},1000);
});
To keep the promise chain going, you can't use setTimeout() the way you did because you aren't returning a promise from the .then() handler - you're returning it from the setTimeout() callback which does you no good.
Instead, you can make a simple little delay function like this:
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
And, then use it like this:
getLinks('links.txt').then(function(links){
let all_links = (JSON.parse(links));
globalObj=all_links;
return getLinks(globalObj["one"]+".txt");
}).then(function(topic){
writeToBody(topic);
// return a promise here that will be chained to prior promise
return delay(1000).then(function() {
return getLinks(globalObj["two"]+".txt");
});
});
Here you're returning a promise from the .then() handler and thus it is chained appropriately.
You can also add a delay method to the Promise object and then directly use a .delay(x) method on your promises like this:
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
Promise.prototype.delay = function(t) {
return this.then(function(v) {
return delay(t, v);
});
}
Promise.resolve("hello").delay(500).then(function(v) {
console.log(v);
});
.then(() => new Promise((resolve) => setTimeout(resolve, 15000)))
UPDATE:
when I need sleep in async function I throw in
await new Promise(resolve => setTimeout(resolve, 1000))
The shorter ES6 version of the answer:
const delay = t => new Promise(resolve => setTimeout(resolve, t));
And then you can do:
delay(3000).then(() => console.log('Hello'));
If you are inside a .then() block and you want to execute a settimeout()
.then(() => {
console.log('wait for 10 seconds . . . . ');
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log('10 seconds Timer expired!!!');
resolve();
}, 10000)
});
})
.then(() => {
console.log('promise resolved!!!');
})
output will as shown below
wait for 10 seconds . . . .
10 seconds Timer expired!!!
promise resolved!!!
Happy Coding!
Since node v15, you can use timers promise API
example from the doc:
import { setTimeout } from 'timers/promises'
const res = await setTimeout(100, 'result')
console.log(res) // Prints 'result'
In node.js you can also do the following:
const { promisify } = require('util')
const delay = promisify(setTimeout)
delay(1000).then(() => console.log('hello'))
For the current LTS its easier and we can use async/await to handle timeouts. Please note that this is the recommended way to use timeout nowadays.
Thenables is not the recommended way.
const { promisify } = require('util')
const sleep = promisify(setTimeout)
async function myFunction() {
await sleep(1e3)
console.log('This will be seen after 1 sec')
await sleep(5e3)
console.log('This will be seen after 5 sec after')
}
const myStuff = new Promise(function (resolve) {
console.log("before timeout");
setTimeout(
function (x) {
console.log("inside the timeout");
resolve(x);
},
3000,
"after timeout"
);
}).then((response) => console.log(response));