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));
Related
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);
}
})();
I want to test the following code:
const poll = (maxTries, interval, channel, stopTime) => {
let reached = 1;
const someInformation = someGetter();
const fetchData = async (resolve, reject) => {
const data = await networkClass.someApiCall();
if (data.stopTime === 1581516005) {
console.log("cond true");
someInformation.meta1 = transFormer(someInformation);
someInformation.meta2 = transFormer(someInformation);
someInformation.meta3 = {
...someInformation.meta1,
data,
};
resolve(someInformation);
} else if (reached < maxTries) {
reached += 1;
console.log("do it again");
setTimeout(fetchData, interval, resolve, reject);
} else {
reject(new Error('max retries reached'));
}
};
return new Promise(fetchData);
};
const checkForUpdates = () => {
setTimeout(() => {
poll(/* max retries */ 10, /* polling interval */ 1000, channel, stopTime)
.then((res) => {
setData(res);
console.log({ res: res.meta3.data });
})
.catch((e) => console.log({ e }));
}, 20000);
};
The test looks like that:
it(`should do stuff`, () => {
jest.spyOn(networkClass, 'someApiCall')
.mockResolvedValueOnce({ stopTime })
.mockResolvedValueOnce({ stopTime })
.mockResolvedValueOnce({ stopTime: 1581516005 });
checkForUpdates();
jest.advanceTimersByTime(40000);
expect(setDataMock).toHaveBeenCalled();
});
That console.log (console.log("do it again");) is only printed once, as if the test would not be able to call a setTimeout within a setTimeout. Do you have any ideas what might help?
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 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();
I have a javascript function with setTimeOut and I am retrying to call same function, if any error from API call.I am calling same function in catch block.Is my node server is going crash and resources will be blocked or it will keep calling getData() function
let retry = ()=> {
setTimeout(() => {
getData()
retry()
}, 3000);
}
let getData = () =>{
Someapi.getData().then((token) => {
console.log(`Data after 3 seconds->${token}`)
}).catch((err) => {
getData()
})
}
I do not know if this work.
let retry = () => {
setTimeout(() => {
getData();
retry();
}, 3000);
};
while (true) {
let getData = () => {
Someapi.getData()
.then(token => {
console.log(`Data after 3 seconds->${token}`);
return false;
})
.catch(err => {
return true;
});
};
}
I use this retry code in my project, it works well in production:
const pause = (duration) => {
return new Promise(resolve => setTimeout(resolve, duration));
};
const retry = (retryTimes, func, delay) => {
return func().catch(
(err) => {
if(retryTimes > 0) {
return pause(delay).then(
() => retry(retryTimes - 1, func, delay * 2)
);
} else {
return Promise.reject(err);
}
}
);
};