I have some example code, but I can't figure out why the console is logging things out of order.
async function myAsyncFunction() {
setTimeout(() => { console.log("1st"); return "something"; }, 500);
}
async function mainline() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => { console.log("0th"); resolve(); }, 500);
});
promise.then(async () => {
return await myAsyncFunction();
})
.then((string) => {
console.log(string);
console.log("2nd");
});
}
mainline();
The console logs:
> 0th
> undefined
> 2nd
> 1st
So clearly my mainline isn't waiting to resolve the async function. What did I do wrong?
Your myAsyncFunction isn't returning anything. You need to wrap it in a promise.
function myAsyncFunction() {
return new Promise( (res, rej) =>
setTimeout(() => { console.log("1st"); res("something"); }, 500) );
}
function myAsyncFunction() {
return new Promise((resolve, reject) => {
setTimeout(() => { console.log("1st"); resolve("something"); }, 500);
});
}
async function mainline() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => { console.log("0th"); resolve(); }, 500);
});
promise.then(async () => {
return await myAsyncFunction();
})
.then((string) => {
console.log(string);
console.log("2nd");
});
}
mainline();
Related
I had a job interview yesterday, and I was given a coding challenge as the following:
// 3. Coding challenge.
// The goal is to make function1/function2 to work only when the constructor has finished its async operations.
// You CAN'T change the notifyUrls function. Imagine it's a 3th party library you don't have control on.
// CAN'T CHANGE THIS.
//===================
function notifyUrls(item, callback) {
asyncOperation(item).then((res) => {
callback(res);
});
}
//===================
const asyncOperation = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('Timeout execute'); resolve(); }, 2000); }); };
const URL1 = 'http://www.somerestapi/get1';
const URL2 = 'http://www.somerestapi/get2';
const URL3 = 'http://www.somerestapi/get3';
class MyClass {
constructor() {
[URL1, URL2, URL3].forEach(item => {
notifyUrls(item, () => { });
});
}
myFunction1() {
// Only start working when constructor finished notifying.
// ...
console.log('myFunction1');
}
myFunction2() {
// Only start working when constructor finished notifying.
// ...
console.log('myFunction2');
}
}
And here is what I did:
// CAN'T CHANGE THIS.
//===================
function notifyUrls(item, callback) {
asyncOperation(item).then((res) => {
callback(res);
});
}
//===================
const asyncOperation = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('Timeout execute'); resolve(); }, 2000); }); };
const URL1 = 'http://www.somerestapi/get1';
const URL2 = 'http://www.somerestapi/get2';
const URL3 = 'http://www.somerestapi/get3';
class MyClass {
constructor() {
this.ready = Promise.all([URL1, URL2, URL3].map((url) => { this.myAsyncCall(url); }));
}
myAsyncCall(item) {
return new Promise((resolve, reject) => {
notifyUrls(item, (res) => { resolve(res); });
});
}
async myFunction1() {
if (await this.ready) {
// Only start working when constructor finished notifying.
// ...
console.log('myFunction1');
}
}
myFunction2() {
// Only start working when constructor finished notifying.
// ...
console.log('myFunction2');
}
}
(async () => {
const myClass = new MyClass();
await myClass.myFunction1();
})();
But the output is:
myFunction1
Timeout execute
Timeout execute
Timeout execute
What I want the output to be is:
Timeout execute
Timeout execute
Timeout execute
myFunction1
How can I work around it?
Thanks.
The problem is in
this.ready = Promise.all([URL1, URL2, URL3].map((url) => { this.myAsyncCall(url); }));
Your map callback doesn't return anything
Either do
this.ready = Promise.all([URL1, URL2, URL3].map((url) => { return this.myAsyncCall(url); }));
or
this.ready = Promise.all([URL1, URL2, URL3].map((url) => this.myAsyncCall(url)));
Adding some coding tips
notifyUrls(item, (res) => {
resolve(res);
});
Can simply be
notifyUrls(item, resolve);
and
const asyncOperation = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
});
};
is just
const asyncOperation = () => new Promise(resolve => setTimeout(resolve, 2000));
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'));
I need such sequence:
🤡lurks in the shadows;
the end
How to achieve such result without touching 'sequential' function?
Achieve sequential run
function who() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 200);
});
}
function what() {
return new Promise(resolve => {
setTimeout(() => {
resolve('lurks');
}, 300);
});
}
function where() {
return new Promise(resolve => {
setTimeout(() => {
resolve('in the shadows');
}, 500);
});
}
async function msg() {
const a = await who();
const b = await what();
const c = await where();
console.log(`${ a } ${ b } ${ c }`);
}
function sequential(){
msg();
console.log('the end');
}
sequential();
I need such sequence:
🤡lurks in the shadows
the end
How to achieve such result without touching 'sequential' function?
Current result is:
the end
🤡lurks in the shadows
function who(data) {
return new Promise(resolve => {
setTimeout(() => {
resolve(data + '🤡');
}, 200);
});
}
function what(data) {
return new Promise(resolve => {
setTimeout(() => {
resolve(data + 'lurks');
}, 300);
});
}
function where(data) {
return new Promise(resolve => {
setTimeout(() => {
resolve(data + 'in the shadows');
}, 500);
});
}
function msg() {
return who('')
.then(what)
.then(where);
}
function sequential(){
return msg()
.then((respo) => {
console.log(JSON.stringify(respo));
console.log('the end');
});
}
sequential();
You can do this!
I have this following piece of code
new Promise((resolve, reject) => {
resolve(apiRequest(data))
reject(console.log('Error'))
}).then(response)
Both methods (resolve and reject) are being fired but I want to call reject only when something goes wrong.
How can I throw an error if something goes wrong on that case?
I checked that but it seems like I can not use an If statement to do that check.
new Promise((resolve, reject) => {
const printResult = apiRequest(data)
console.log(printResult) //Outputs Promise {<pending>}
resolve(printResult) //Then it works
reject(console.log('Error'))
}).then(response)
What would be the correct approach to reject a promise?
The easiest way would be with an if condition. i.e
new Promise((resolve, reject) => {
// do something...
if(somethingGoodHappened) {
resolve(data)
} else {
reject(error)
}
})
But usually when dealing with async requests, the thing you are calling will often be returning a promise, so you can attach the then and catch callbacks there.
apiRequest(data)
.then((result) => {
// all good
})
.catch((err) => {
console.log(err)
})
const mock_api = () => new Promise((res, rej) => {
const number = Math.floor((Math.random() * 100) + 1);
setTimeout(() => {
if (number%2==0) return res('randomly RESOLVED')
return rej('randomly REJECTED')
}, 2000)
})
const async_promise = () => new Promise(async (resolve, reject) => {
try {
const resolvedPromise = await mock_api()
resolve(resolvedPromise)
} catch (e) {
reject(e)
}
})
const classicPromise = () => new Promise((resolve, reject) => {
mock_api()
.then(resolve)
.catch(reject)
})
const makeAsyncRequest = async () => {
try {
const data = await async_promise()
console.log('ASYNC AWAIT RESOLVE', data)
} catch (e) {
console.log('ASYNC AWAIT ERR', e)
}
}
makeAsyncRequest()
classicPromise()
.then(r => console.log('PROMISE CHAIN RESOLVE', r))
.catch(e => console.log('PROMISE CHAIN ERR', e))
Because of you resolve before reject so it cannot run into reject,
You can use:
if (printResult) {
resolve(printResult)
} else {
reject(console.log('Error'))
}
You can catch exceptions and return them as rejected Promises
function asyncFunc() {
try {
doSomethingSync();
return doSomethingAsync()
.then(result => {
···
});
} catch (err) {
return Promise.reject(err);
}
}
Always check for err if there is any err return a promise (example below)
// Return new promise
return new Promise(function(resolve, reject) {
// Do async job
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})
This question already has answers here:
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 6 years ago.
I've promise chain which the response in the first chain should be used later on in the chain (in 4 & 6) places, I use some global variable to handle it but this is not the right way ,there is a better way to achieve this with promise?
This is some illustration for the issue...
var step1 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 1");
resolve(20);
}, ms);
})
}
var step2 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 2");
resolve();
}, ms);
})
};
var step3 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 3");
resolve();
}, ms);
})
};
var step4 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("Step 4, run : " + ms );
resolve();
}, ms);
})
};
var globalVar = null;
//Promise chain
step1(500)
.then((res) => {
//Here I keep the response in global variable to use later on
globalVar = res;
log(res);
return step2(300);
}).then(() => {
return step3(200);
}).then(() =>{
//Here I need to use the res from the first promise
var lclvar = globalVar +200 ;
return step4(lclvar);
}).catch((err) => {
log(err);
});
I found this but this is not helping in this case(at least didn't able to handle it)
How do I access previous promise results in a .then() chain?
You could just nest the step2, step3, etc calls inside the first handler, then res would be available to them all
step1(500).then((res) => {
log(res);
return step2(300)
.then(() => step3(200))
.then(() => step4(res + 200));
}).catch((err) => {
log(err);
});
If you really wan to chain this actually words. the idea is a bus parameter traveling along the way.It's created in the first promise as a closure.
you can run this code:
log=console.log
var step1 = (ms) => {
var Buss={p1:20};
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 1");
resolve(Buss);
}, ms);
})
}
var step2 = (ms,bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 2");
resolve(bus);
}, ms);
})
};
var step3 = (ms,bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 3");
resolve(bus);
}, ms);
})
};
var step4 = (bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("Step 4, run : " + bus.p1 );
log("bus arrives:",bus);
resolve(bus);
}, bus.p1);
})
};
//Promise chain
step1(500)
.then((res) => {
//Here I keep the response in global variable to use later on
//globalVar = res;
log(res);
return step2(300,res);
}).then((res) => {
return step3(200,res);
}).then((res) =>{
//Here I need to use the res from the first promise
//var lclvar = globalVar +200 ;
res.p1+=200;
return step4(res);
}).catch((err) => {
log(err);
});