How to fire two asynchro funcs synchronously? - javascript

I have a function:
fn = () => {
fn1(); // call first
fn2(); // call only when listener is done from fn1
}
and these two fns:
fn1 = () => {
const k1 = new Image();
k1.src = someSrc;
k1.addEventListener('load', () => some func {});
}
My question: What to do to make fn2 function fire only when fn1 is called and load event is fired?
const fn = async () => {
await fn1(); // call first
await fn2(); // call only when listener is done from fn1
}
const fn1 = async () => {
const k1 = new Image();
k1.src = await 'https://www.medicalnewstoday.com/content/images/articles/326/326253/corgi-and-terrier-running.jpg';
await k1.addEventListener('load', async () => await console.log('it should log first'));
}
const fn2 = async () => {
console.log('then second');
}
fn();

If you want to work with async/await, as mentioned in the comments, then you'll need to create and return a promise:
const fn1 = () => {
return new Promise((resolve) => {
const k1 = new Image();
k1.src = someSrc;
k1.addEventListener('load', resolve);
});
}
Then you can await this promise in an async function:
const fn = async () => {
await fn1();
fn2();
}

Try something like this:
const fn1 = () => {
const k1 = new Image();
k1.src = 'https://www.medicalnewstoday.com/content/images/articles/326/326253/corgi-and-terrier-running.jpg';
document.body.appendChild(k1);
return new Promise(resolve => {
k1.addEventListener('load', () => resolve('I am done!'));
})
}
const fn2 = () => {
console.log('then second');
}
const fn = async () => {
const a = await fn1(); // call first
console.log(a);
fn2(); // call only when listener is done from fn1
}
fn();

Related

Multiple same Async Await function only Triggered the Last One

const fun = (x) => {
console.log(`Meth... ${x}`);
setTimeout(() => {
onReceive(`Fun Received: ${x}`);
}, 100);
return x;
}
const publish = () => {
return new Promise(resolve => {
window.onReceive = (token) => {
resolve(token);
}
});
}
const Inst = () => {
const getAs = async(x) => {
console.log(`Getting As ----- ${x}`);
const res = await publish(fun(x));
console.log(`Res is '${res}' ---- ${x}`);
}
return {
getAs,
}
}
const inst = Object.freeze(Inst());
const a = async() => {
await inst.getAs(1);
await inst.getAs(2);
await inst.getAs(3);
await inst.getAs(4);
await inst.getAs(5);
};
a();
const b = async() => {
await inst.getAs(4);
await inst.getAs(5);
await inst.getAs(6);
await inst.getAs(7);
};
b();
// Comment or remove `b()` to see the different result in Console
I got confused why the function only called the last async await (b() from the example). Why inside of a() seems like didn't get called at all??
If I comment / remove b(), all inside of a() will get call.
Need helps / explanation to resolve such issue 🙏.

Async operations when instance created

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

Javascript cancel await for animation sequence?

I have a function like this:
const init = async () => {
const els = [...]; //array of html elements
els[0].classList.add('hidden');
await sleep(200);
els[1].classList.remove('hidden');
await sleep(500);
els[3].classList.remove('hidden');
await sleep(4000);
els[3].classList.add('hidden');
els[2].classList.remove('hidden');
els[1].classList.add('hidden');
await sleep(800);
els[3].classList.add('out');
els[4].classList.remove('hidden');
}
As you can see there's a 4 second await in there. I want to, using an external function that comes from a click, to be able to skip that 4000ms delay.
const cancelAnimation = () => {
// whatever
}
I thought of using a flag variable to change the number from 4000 to 500 for example, but if it already gotten into that sleep(4000) it doesn't matter cause the number won't change.
So, is there any way to cancel this out?
Btw, this is the code from the sleep function:
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
You can make your promise cancelable:
const cancelableSleep = (ms) => {
let timeout;
return {
promise: new Promise((resolve) => {
timeout = setTimeout(resolve, ms);
}),
cancel() {
clearTimeout(timeout);
},
};
};
const init = async () => {
const cancelable = cancelableSleep(10000);
//simulate click in 2 seconds
setTimeout(() => cancelable.cancel(), 2000);
console.log("sleeping");
await cancelable.promise;
console.log("awake");
};
init();
A bit of magic (https://codesandbox.io/s/green-dream-u2yxk?file=/src/index.js) :)
import CPromise from "c-promise2";
const init = () => CPromise.from(function* () {
let skip = false;
let promise;
this.on("signal", (type) => {
if (type === "skip") {
promise ? promise.cancel() : (skip = true);
}
});
console.log("stage1");
yield CPromise.delay(200);
console.log("stage2");
yield CPromise.delay(500);
console.log("stage3");
if (!skip) {
yield (promise = CPromise.delay(4000)).cancelled();
}
console.log("stage4");
yield CPromise.delay(800);
console.log("stage5");
});
const task = init();
console.log(task instanceof Promise); // true
setTimeout(() => {
task.emitSignal("skip");
}, 800);

Javascript: Does it matter where 'let' variables are initialized inside a block?

The following behavior of Javascript is a complete mystery to me. The following code snippet does not work:
let someFunctionOne = async () => (new Promise(resolve => setTimeout(resolve(1), 1000)))
let someFunctionTwo = async () => (new Promise(resolve => setTimeout(resolve(2), 1000)))
let someFunctionThree = async () => (new Promise(resolve => setTimeout(resolve(3), 1000)))
let myFunction = async () => {
let resultOne
if (true) {
let resultTwo, resultThree // <-- doesn't work
if (false) {
throw new Error('Something went wrong')
}
const promiseOne = someFunctionOne()
const promiseTwo = someFunctionTwo()
const promiseThree = someFunctionThree()
[resultOne, resultTwo, resultThree] = await Promise.all([
promiseOne,
promiseTwo,
promiseThree]
)
resultOne = {resultOne, resultTwo, resultThree}
}
return resultOne
}
let result = await myFunction()
console.log(result)
This throws the following error:
ReferenceError: Cannot access 'promiseThree' before initialization
However, when the initialization of the two variables is put right above the Promise.all() call it does work:
let someFunctionOne = async () => (new Promise(resolve => setTimeout(resolve(1), 1000)))
let someFunctionTwo = async () => (new Promise(resolve => setTimeout(resolve(2), 1000)))
let someFunctionThree = async () => (new Promise(resolve => setTimeout(resolve(3), 1000)))
let myFunction = async () => {
let resultOne
if (true) {
if (false) {
throw new Error('Something went wrong')
}
const promiseOne = someFunctionOne()
const promiseTwo = someFunctionTwo()
const promiseThree = someFunctionThree()
let resultTwo, resultThree // <-- does work
[resultOne, resultTwo, resultThree] = await Promise.all([
promiseOne,
promiseTwo,
promiseThree]
)
resultOne = {resultOne, resultTwo, resultThree}
}
return resultOne
}
let result = await myFunction()
console.log(result)
Why on earth is the second code snippet working and the first one isn't? For both, the variable initialization of resultTwo and resultThree happen before they are used...
Thanks

async/await function does not wait for setTimeout to finish

I'm using await within an async function execute functions in a particular order, if you see here - I wanted startAnim to wait until hideMoveUI had finished executing to execute itself.
Though my console log returns:
startAnim
hideMoveUI
My code:
async function printAll() {
await hideMoveUI();
await startAnim();
}
printAll();
hideMoveUI = () => {
setTimeout(() => {
console.log('hideMoveUI');
}, 3000);
}
startAnim =() => {
setTimeout(() => {
console.log('startAnim');
}, 500);
}
Is setTimeout an async function?
How can I make the second function wait for the first one to finish? any help or advice is appreciated. Thank you in advance.
Two issues:
Your hideMoveUI/startAnim functions have no return value, so calling them results in undefined. await undefined is undefined.
If you fix #1, await would be waiting on a timer handle, which on browsers is a number. There's no way for await to know that number is a timer handle.
Instead, give yourself a promise-enabled setTimeout and use it.
E.g.:
const wait = (delay, ...args) => new Promise(resolve => setTimeout(resolve, delay, ...args));
const hideMoveUI = () => {
return wait(3000).then(() => console.log('hideMoveUI'));
};
const startAnim = () => {
return wait(500).then(() => console.log('startAnim'));
};
async function printAll() {
await hideMoveUI();
await startAnim();
}
printAll()
.catch(e => { /*...handle error...*/ });
or of course
const wait = (delay, ...args) => new Promise(resolve => setTimeout(resolve, delay, ...args));
const hideMoveUI = async () => {
await wait(3000);
console.log('hideMoveUI');
};
const startAnim = async () => {
await wait(500);
console.log('startAnim');
};
async function printAll() {
await hideMoveUI();
await startAnim();
}
printAll()
.catch(e => { /*...handle error...*/ });

Categories

Resources