How to write await() for multiple promises in JavaScript? - javascript

I m trying to write await for multiple promises, instead of nested functions.
Please take a look at the below code i tried, as it will explain better than me.
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () =>
new Promise((resolve) => async () => {
// console.log(1);
return resolve(await fun2(1));
});
// Fun 2
const fun2 = (value) =>
new Promise((resolve) => async (value) => {
value = value + 1;
// console.log(value);
return resolve(await fun1(value));
});
// Fun 1
const fun1 = () =>
new Promise((resolve) => (value) => {
value = value + 1;
// console.log(value);
return resolve(value);
});
fun3();
};
main();
I tried console logging to debut but I m getting nothing in the console.
Any help is greatly appreciated.

the syntax is wrong, its not new Promise((resolve) => async () => {}) with 2 arrow, but new Promise((resolve) => {}) also you can call promise function without await
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () => new Promise(resolve => {
//console.log(1);
return resolve(fun2(1));
});
// Fun 2
const fun2 = (value) => new Promise(resolve => {
value = value + 1;
//console.log(value);
return resolve(fun1(value));
});
// Fun 1
const fun1 = (value) => new Promise(async (resolve) => {
value = value + 1;
console.log('sleep 3 seconds');
await new Promise(r => setTimeout(r, 3000));
console.log(value);
return resolve(value);
});
fun3();
};
main();

If you want to call await inside a Promise callback, you can do this:
const p = new Promise((resolve) => {
(async () => {
const res = await anotherPromise();
resolve(res);
})();
});
So with this in mind, you can rewrite your functions like this:
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () =>
new Promise((resolve) => {
(async () => {
resolve(await fun2(1));
})();
});
// Fun 2
const fun2 = (value) =>
new Promise((resolve) => {
value = value + 1;
(async () => {
resolve(await fun1(value));
})();
});
// Fun 1
const fun1 = (value) =>
new Promise((resolve) => {
value = value + 1;
(async () => {
resolve(value);
})();
});
return await fun3();
};
// ans: 3
console.log(await main());
If you want to do it in pure async/await, you may do this:
const main = async () => {
const fun1 = async (value) => value + 1;
const fun2 = async (value) => await fun1(value + 1);
const fun3 = async () => await fun2(1);
return await fun3();
}
// output: 3
console.log(await main());

I hope this example works for you.
console.clear();
function wait(ms, data) {
return new Promise( resolve => setTimeout(resolve.bind(this, data), ms) );
}
/**
* These will be run in series, because we call
* a function and immediately wait for each result,
* so this will finish in 1s.
*/
async function series() {
return {
result1: await wait(500, 'seriesTask1'),
result2: await wait(500, 'seriesTask2'),
}
}
/**
* While here we call the functions first,
* then wait for the result later, so
* this will finish in 500ms.
*/
async function parallel() {
const task1 = wait(500, 'parallelTask1');
const task2 = wait(500, 'parallelTask2');
return {
result1: await task1,
result2: await task2,
}
}
async function taskRunner(fn, label) {
const startTime = performance.now();
console.log(`Task ${label} starting...`);
let result = await fn();
console.log(`Task ${label} finished in ${ Number.parseInt(performance.now() - startTime) } miliseconds with,`, result);
}
void taskRunner(series, 'series');
void taskRunner(parallel, 'parallel');

fun3() is an async function so you have to put await before the call.
var main = async () => {
// Fun 3
const fun3 = () => new Promise(resolve => {
//console.log(1);
return resolve(fun2(1));
});
// Fun 2
const fun2 = (value) => new Promise(resolve => {
value = value + 1;
//console.log(value);
return resolve(fun1(value));
});
// Fun 1
const fun1 = (value) => new Promise(async (resolve) => {
value = value + 1;
console.log('sleep 3 seconds');
await new Promise(r => setTimeout(r, 3000));
console.log(value);
return resolve(value);
});
await fun3();
};
main();

Related

convert this code to a version without "async - await"

I'm trying to convert this code to a version without "async - await". Code converted to use (all) promises without async and await. But my console print undefined for time. Can someone help me? Its for a homework of my College.
Thanks very much
(async() => {
function exibirErro(err) {
console.log(err.message);
}
const f1 = async(tempo) => {
return new Promise((resolve, reject) => {
const f = () => reject(new Error('Rejeitado'));
console.log(`Aguardando ${tempo} segundos...`);
setTimeout(f, tempo);
});
};
const f2 = async(x) => {
if ((Math.random() * 10) % 2 == 0) {
throw new Error('Ops');
}
return Promise.resolve(1000 * x);
};
const f3 = async() => {
const r = await new Promise(resolve => resolve(2));
const t = await f2(r);
await f1(t);
};
try {
await f3();
} catch (err) {
exibirErro(err);
}
})();
My code:
function exibirErro(err) {
console.log(err.message);
}
function f1(tempo) {
return new Promise((resolve, reject) => {
const f = () => reject(new Error('Reject'));
console.log(`wait ${tempo} seconds...`);
setTimeout(f, tempo);
})
.then((x) => {
if ((Math.random() * 10) % 2 == 0) {
throw new Error('Ops');
}
return Promise.resolve(1000 * x);
})
.then((t) => {
return Promisse.resolve(f1(t));
}).catch((e) => {
exibirErro(e);
})
}
f1();
Starting with your wrapper function -
(async() => {
First we have a normal synchronous function, nothing to change here -
function exibirErro(err) {
console.log(err.message);
}
Next we have function f1 which uses the async keyword but does not await anything. All you have to do here is remove the async keyword -
const f1 = async(tempo) => {
return new Promise((resolve, reject) => {
const f = () => reject(new Error('Rejeitado'));
console.log(`Aguardando ${tempo} segundos...`);
setTimeout(f, tempo);
});
};
Next we have function f2, which again uses async but does not await anything. Simply remove async -
const f2 = async(x) => {
if ((Math.random() * 10) % 2 == 0) {
throw new Error('Ops');
}
return Promise.resolve(1000 * x);
};
Then we have function f3 that awaits two things, r and t -
const f3 = async() => {
const r = await new Promise(resolve => resolve(2));
const t = await f2(r);
await f1(t); // missing return
};
We can rewrite f3 using .then -
const f3 = () =>
new Promise(resolve => resolve(2)).then(r =>
f2(r).then(t =>
f1(t)
)
)
Finally you have try/catch -
try {
await f3();
} catch (err) {
exibirErro(err);
}
Simply use .catch instead -
f3().catch(exibirErro)
And the closing syntax for the async wrapper function. The wrapper will not be needed in the final version.
})();
Here it is all together now -
function exibirErro(err) {
console.log(err.message);
}
const f1 = tempo => {
return new Promise((resolve, reject) => {
const f = () => reject(new Error('Rejeitado'));
console.log(`Aguardando ${tempo} segundos...`);
setTimeout(f, tempo);
});
};
const f2 = x => {
if ((Math.random() * 10) % 2 == 0) {
throw new Error('Ops');
}
return Promise.resolve(1000 * x);
};
const f3 = () => {
return new Promise(resolve => resolve(2)).then(r =>
f2(r).then(t =>
f1(t)
)
)
}
f3().catch(exibirErro)

Function calls from data.map are not executed synchronously

I am trying to call same function from map. Depending upon number of entries function will be called.
Here is my code
getDetails = (inputData) => {
const data = {
accountName: "test",
};
let url = `/rest/jarvis/reports/v1/getData`;
let thisdata = this;
post(url, data)
.then((response) => {
if (
response.data &&
response.data.sb &&
response.data.sb.length > 0
) {
this.props.bs.betDetails = {
data: [...response.data.sportsbookBets],
exportAccesses: response.data.exportAccesses,
};
this.props.bs.betDetails.data.map((value, index) => {
console.log("Index Value --->", index);
this.getEventDetails(value, index);
}),
this.updateReducer({
...this.props.bs,
});
}
}
}
getEventDetails = async (value, index) => {
let _this = this;
let myPromise = new Promise(function (myResolve, myReject) {
console.log("Index Value at the entry--->", index);
const data = {
accountName: "test",
};
let url = `/rest/jarvis/reports/v1/getBetEventData`;
post(url, data).then((response) => {
if (response.data) {
console.log("Index Value inside--->", index);
_this.eventIdIndexMap.set(
list.eventId != null
? list.eventId
: _this.props.bs.betEventRequest.EventId,
index
);
_this.props.bs.testEventDetails[
_this.eventIdIndexMap.get(
list.eventId != null
? list.eventId
: _this.props.bs.betEventRequest.EventId
)
] = _this.props.bs.betEventResponse;
}}}
await myPromise;
}
Here problem I am facing is inside post call of 'getEventDetails' index values are not getting in sequence.
I have used promise await and async but it is not working.
Can someone please tell me how to get it properly ?
map calls its callback function without await. You can use asynchronous functions in the callback function but they won't be executed in order.
But you can create your own map with await:
async function map(array, cb) {
const result = [];
for (const element of array) {
result.push(await cb(element));
}
return result;
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
console.log(await map([3, 2, 1], async el => { await sleep(el * 100); return 2 * el; }));
})();
or create your own Array.prototype.syncMap:
Array.prototype.syncMap = async function(cb) {
const result = [];
for (const element of this) {
result.push(await cb(element));
}
return result;
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
console.log(await [3, 2, 1].syncMap(async el => { await sleep(el * 100); return 2 * el; }));
})();
It looks like you don't even need a result. You can write your own Array.prototype.syncForEach:
Array.prototype.syncForEach = async function(cb) {
for (const element of this) {
await cb(element);
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
[3, 2, 1].syncForEach(async el => { await sleep(el * 100); console.log(2 * el); });
[30, 20, 10].forEach(async el => { await sleep(el * 10); console.log(2 * el); });
As you can see in the output the functions in syncForEach are executed in order and the functions in forEach are executed out of order.

javascript - cancel awaited function before it is called again

On incoming webrtc call, I open a modal to show user a message about media permissions and await this till the user presses OK button on the modal.
I do it like this:
async function myMessage(){
$('#id_my_message_modal').modal('show');
return new Promise(resolve =>
$('#id_my_message_button').on('click', () => {
$('#id_my_message_modal').modal('hide');
resolve();
}
)
);
}
then
await myMessage();
The issue I am facing now is if await myMessage(); is called again while the previous call has still not returned(i.e user hasn't pressed OK button). I want a way to cancel any previous await myMessage();, if exists, before it is called again.
Is there any way to do it?
The first approach (Live demo)- add every call of the async function to the queue, so you will get a sequence of dialogs with the result returning (close/accept/whatever).
// decorator from my other answer
function asyncBottleneck(fn, concurrency = 1) {
const queue = [];
let pending = 0;
return async (...args) => {
if (pending === concurrency) {
await new Promise((resolve) => queue.push(resolve));
}
pending++;
return fn(...args).then((value) => {
pending--;
queue.length && queue.shift()();
return value;
});
};
}
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const myMessage = asyncBottleneck(async function () {
const $modal = $("#id_my_message_modal");
$modal.modal("show");
const result = await new Promise((resolve) =>
$modal.on("click", "button", (e) => {
$modal.modal("hide");
$modal.off("click", "button");
resolve($(e.target).data("action"));
})
);
await delay(250);
return result;
});
The second approach (Live demo)- multiplexing the fn calls, when every await of the function will return the same result; Compare console output of the live demos.
function singleThread(fn) {
let promise = null;
return function (...args) {
return (
promise ||
(promise = fn(...args).finally(() => {
promise = null;
}))
);
};
}
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const myMessage = singleThread(async function () {
const $modal = $("#id_my_message_modal");
$modal.modal("show");
const result = await new Promise((resolve) =>
$modal.on("click", "button", (e) => {
$modal.modal("hide");
$modal.off("click", "button");
resolve($(e.target).data("action"));
})
);
await delay(250);
return result;
});
$("#btn-run").on("click", async () => {
myMessage().then((c) => console.log(`First result: ${c}`));
await myMessage().then((c) => console.log(`Second result: ${c}`));
myMessage().then((c) => console.log(`Third result: ${c}`));
});
The third way- closing the previous modal with its promise rejecting (Live Demo open console there to see the result).
import CPromise from "c-promise2";
const showModal = (() => {
let prev;
return (id, text = "") => {
prev && prev.cancel();
return (prev = new CPromise((resolve, reject, { onCancel }) => {
const $modal = $(id);
text && $modal.find(".modal-body").text(text);
$modal.modal("show");
const dispose = () => {
$modal.modal("hide");
$modal.off("click", "button");
};
$modal.on("click", "button", function (e) {
dispose();
resolve($(this).data("action"));
});
$modal.on("hidden.bs.modal", () => {
setTimeout(() => resolve("close"));
});
onCancel(dispose);
})).finally(() => (prev = null));
};
})();
$("#btn-run").on("click", async () => {
showModal("#id_my_message_modal", "First message").then(
(c) => console.log(`First modal result: ${c}`),
(e) => console.warn(`First modal fail: ${e}`)
);
showModal("#id_my_message_modal", "Second message").then(
(c) => console.log(`Second modal result: ${c}`),
(e) => console.warn(`Second modal fail: ${e}`)
);
const promise = showModal("#id_my_message_modal", "Third message")
.then(
(c) => console.log(`Third modal result: ${c}`),
(e) => console.warn(`Third modal fail: ${e}`)
)
.timeout(5000)
.then(() => {
return showModal(
"#id_my_message_modal2",
"Blue Pill or Red Pill?"
).then((v) => console.log(`Pill: ${v}`));
});
/*setTimeout(()=>{
promise.cancel(); you can cancel the modal from your code
}, 1000);*/
});

Create a Promise that resolves when variable is not undefined

I'm trying to Create a Promise that resolves when variable is not undefined.
Code example
https://codesandbox.io/s/quizzical-feynman-ktvox?file=/src/index.js
let fetchedPromise = new Promise((resolve, reject) => {
const check = ()=>{
setTimeout(() =>{
console.log("checking")
if (dataFetched) resolve(dataFetched);
else check()
}, 100);
}
check()
});
const waitForDataFromAnotherComponent = async () => {
let result = await fetchedPromise;
console.log("Result: ", result);
};
const assignData = () => {
setTimeout(() => {
dataFetched = 1000;
console.log(dataFetched);
}, 5000)
};
waitForDataFromAnotherComponent();
assignData();
This works but I find it inefficient as it's callstack prone and seems wrong.
Other non-working solutions I've tried:
//-------------SOLUTION 1
let fetchedPromise = new Promise((resolve, reject) => {
const check = ()=>{
if (dataFetched) resolve(dataFetched);
else check()
}
check()
});
//--------------------SOLUTION 2
let fetchedPromise = new Promise((resolve, reject) => {
if (dataFetched) resolve(dataFetched);
});
Scenario
I need a function like solution 3 that doesn't rely on setTimeout
Solved by using Javascript Proxy
Basically I assign a Proxy Object to dataFetched that listens to changes.
I re-create the function of listening due to the fact that it must include resolve()
let dataFetched
let x = {
aListener: function (val) {},
set a(val) {
dataFetched = val;
this.aListener(val);
},
get a() {
return dataFetched;
},
registerListener: function (listener) {
this.aListener = listener;
}
};
let fetchedPromise = new Promise((resolve, reject) => {
x.registerListener(function (val) {
console.log("yeyyyyyyyyyyyyyyy");
if (dataFetched) resolve(dataFetched);
});
});
const waitForDataFromAnotherComponent = async () => {
let result = await fetchedPromise;
console.log("Result: ", result);
};
const assignData = async () => {
await new Promise((resolve, reject) =>
setTimeout(() => {
x.a = 1000;
console.log(dataFetched);
resolve(dataFetched);
}, 1000)
);
};
waitForDataFromAnotherComponent();
assignData();
EDIT
Actually it's possible to externalize the resolve() function of the promise but with some downsides as stated here
example
let dataFetched
var promiseResolve, promiseReject;
let x = {
aListener: function (val) {
if (dataFetched) promiseResolve(dataFetched);
},
set a(val) {
dataFetched = val;
this.aListener(val);
},
get a() {
return dataFetched;
},
registerListener: function (listener) {
this.aListener = listener;
}
};
let fetchedPromise = new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});

Return dependent promises sequentially inside loop

I'm working on shopify integration.
We receive an array items then loop through them and add them a new model (func1) then I need to use that result from the first and add it to a schedule (func2).
I need this functions to run sequentially because I'm adding the results to a schedule and if I have two results for the same date and they don't yet exist in the database if the they run in parallel it creates 2 separate entries in the database instead of one entry with the two values.
The way I need to return is func1, func2, func1, func2....
But at the moment is returning func1, func1...func2, func2...
This is a simplified example of what I need to accomplish.
const func2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
return console.log('func2');
}, 3000);
});
};
const func1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Func1');
func2();
}, 1000);
});
};
const array = [1, 2, 3, 4, 5];
const test = () => {
array.map(x => {
func1();
});
};
test();
If there is something that isn't clear please let me know.
Thanks
you can use async/await and for loop in order do create a synced like iteration. and use it again in your func1 in order to reslove
const func2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('func2');
resolve();
}, 3000);
});
};
const func1 = () => {
return new Promise( (resolve, reject) => {
setTimeout(async () => {
console.log('Func1');
await func2();
resolve();
}, 1000);
});
};
const array = [1, 2, 3, 4, 5];
const test = async () => {
for(let i=0;i<array.length;i++){
await func1();
}
};
test();
This is the perfect place to use the traverse function:
const traverse = (xs, f) => xs.reduce((promise, x) =>
promise.then(ys => f(x).then(y => Promise.resolve(ys.concat([y])))),
Promise.resolve([]));
const times2 = x => new Promise(resolve => setTimeout(() => {
console.log("times2", x);
resolve(2 * x);
}, 1000));
const minus1 = x => new Promise(resolve => setTimeout(() => {
console.log("minus1", x);
resolve(x - 1);
}, 1000));
const xs = [1,2,3,4,5];
const ys = traverse(xs, x => times2(x).then(minus1));
ys.then(console.log); // [1,3,5,7,9]
Hope that helps.
const func2 = async (modalValue) => {
let result = modalValue*5;
console.log(`Function2 result: ${result}`)
return result;
};
async function getModalValue(i){
// rest of your Code
return { modal: i*2}
}
const func1 = async (item) => {
let {modal} = await getModalValue(item);
console.log(`Function1 modal: ${modal}`)
await func2(modal);
};
const array = [1, 2, 3, 4, 5];
const test = async () => {
for(let i=0;i<array.length;i++){
await func1(array[i]);
}
};
test().then((resp)=> {console.log("Completed")})
.catch((err)=>{console.log("failure")})

Categories