JavaScript getting array index from promise - javascript

The script below returns promise, there is an array inside it with two index, i want to get index=0 and index=1 separately and output them, how can i do it without using console.log?
async function a1(callback) {
var a = 2 + 2;
return await [a, callback()];
}
async function a2() {
var b = 2 + 3;
return await b;
}
console.log(a1(a2));
My question for Artash Grigoryan

In javascript, async functions always return promise.
I am not entirely sure about your intentions here, but looking at your drawing I would assume that you need to add an extra await on lines 3 and 9.
This code should work for you:
async function a1(callback) {
var a = 2 + 2;
return await [a, await callback()];
}
async function a2() {
var b = 2 + 3;
return await b;
}
await a1(a2);
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

I don't really understand why without console.log, but You can do this:
async function main() {
console.error(await a1(a2));
}
async function a1(callback) {
var a = 2 + 2;
return await [a, callback()];
}
async function a2() {
var b = 2 + 3;
return await b;
}
main();

a2 is an async function , so callback() wont be resolved here in this statement return await [a,callback()].
You can check if the callback is of type AsyncFunction , if so then you can wait for it to get resolved before returning the value
async function a1(callback) {
var a = 2 + 2;
if (callback.constructor.name === 'AsyncFunction') {
const m = await callback().then(val => val)
return [a, m]
}
return await [a, callback];
}
async function a2() {
var b = 2 + 3;
return await b;
}
a1(a2).then(d => console.log(d))

Related

Generator next parameter in `for await`

When you have an async generator, you can call next(x) to return a result to the generator.
async function* generate() {
for (let i = start; i <= 5; i++) {
const result = yield i;
console.log("result", result)
}
}
;(async () => {
const generator = generate()
await generator.next(1)
await generator.next(2)
})();
This will print 1 and 2 as this is the next parameter that is passed as a result back to the generator.
How to replicate this same behaviour but using await for ?
for await (let value of generate()) {
// ... no way to send `next` parameter here
}

how to create two Async functions which after waiting for 10 sec returns sum of any number of arguments in javascript

How to Create two async functions, where first function will wait for 10 sec and returns sum of any numbers of argument of type number(using the spread operator) and another will wait for the first function to finish and add 10 more to the return value of first function and finally returns the output.
I'm thankful for any help as these are pretty new for me....
I have tried this ...
var a=0;
setTimeout(function() { Addition(); }, 10000);
async function Addition()
{
for (var i=0; i < arguments.length; i++) {
a += arguments[i];
}
return a;
}
async function secondFunction()
{
await Addition();
a = a + 10;
return a;
};
console.log(Addition(2, 3));
You can use the combination of returning a resolved Promise and setTimeout. In the first async function you're awaiting the Promise to be resolved, and that will only happen after the setTimeout function runs for 10 seconds and then it would return the resolve argument.
async function first(...numbers) {
const result = numbers.reduce((x, y) => x + y);
await new Promise(resolve => setTimeout(resolve, 10000));
return result;
}
function second(n1) {
return n1 + 10;
}
(async () => {
const result1 = await first(10, 10, 10, 10);
const result2 = second(result1);
console.log(result2); // results in 50
})();
You really don't need to use asynchronous functions apart from the setTimeout which we use for the timing.
You can just pass the return value of the first function into the second function
let numberArray = [[10, 5, 25], [-3, 4, 7], [30, 30, 30]];
setTimeout(() => {
numberArray.forEach(array => secondFunction(Addition(...array)));
}, 10000);
function Addition() {
let a = 0;
for (let i = 0; i < arguments.length; i++) {
a += arguments[i];
}
return a;
}
function secondFunction(a) {
a += 10;
return a;
};

Async/Await is not working as expected with for loop statement

I am new to Javascript and nodejs. While trying to understand how promises and callbacks work, i tried calling a function in a 'for' loop as shown below. What i was trying to achieve is to print 'i' value every 2 seconds using promises. However, the program waits for 2 seconds and prints i value 3 times and exits.
for(let i = 0; i < 3 ; i++){
func(callback,i);
}
async function func(callback,i){
await callback(i);
}
function callback(i){
return new Promise((res,rej) =>{
setTimeout(()=>{
console.log('i = ',i)
res();
}, 2000);
})
}
Can anybody please help me understand why this is happening?
You are pretty close. The missing information is async functions (your func()) implicitly returns an AsyncFunction object which implicitly returns a Promise itself too (doc).
Your code using immediately invoked function expression would be
(async () => {
for(let i = 0; i < 3 ; i++){
await func(callback,i);
}
})()
async function func(callback,i){
await callback(i);
}
function callback(i){
return new Promise((res,rej) =>{
setTimeout(()=>{
console.log('i = ',i)
res();
}, 2000);
})
}
Please note now in most of the browsers is natively available the construct for await..of (doc). You can try experimenting this one too.
You can just wrap your loop with async immediately executed function and add await within it (as was already suggested here):
(async () => {
for(let i = 0; i < 3 ; i++){
await callback(i);
}
})();
function callback(i){
return new Promise((res,rej) =>{
setTimeout(()=>{
console.log('i = ',i)
res();
}, 2000);
})
}
Here is my original answer before Bergi's edit:
(async () => {
for(let i = 0; i < 3 ; i++){
await func(callback,i);
}
})()
async function func(callback,i){
await callback(i);
}
function callback(i){
return new Promise((res,rej) =>{
setTimeout(()=>{
console.log('i = ',i)
res();
}, 2000);
})
}
You need to wait for async function to complete
for(let i = 0; i < 3 ; i++){
await func(callback,i);
}
But since you can't use await keyword in the global scope, you will need to wrap your for loop in an async function, and than call it
async function myTest(){
for(let i = 0; i < 3 ; i++){
await func(callback,i);
}
}
myTest()
Here are some functions which help you understand how promises work with Arrays, where we make common mistakes.
function promiseFunction(v) {
return new Promise((resolve) => {
setTimeout(() => resolve(v), 1000);
});
}
function f1() {
[1, 2, 3, 4]. forEach(async(i) => {
const v = await promiseFunction(i);
console.log(`-f1 v- ${v}<br/>`);
});
console.log('all done<br/>');
}
async function f2() {
await Promise.all([1, 2, 3, 4].map(async(i) => {
const v = await promiseFunction(i);
console.log(`-f2 v- ${v}<br/>`);
}));
console.log('all done<br/>');
}
async function f3() {
await [1, 2, 3, 4].reduce((p, i) => {
return p.then(async () => {
const v = await promiseFunction(i);
console.log(`-f3 v- ${v}<br/>`);
});
}, Promise.resolve());
console.log('all done<br/>');
}
async function func() {
console.log('f1');
await f1();
console.log('f2');
await f2();
console.log('f3');
await f3();
}
func();
f1() will print all done first and then print 1,2,3,4 at once after a second.
f2() will print 1,2,3,4 at once after a second then print all done.
f3() will print 1,2,3,4 in every second, and then print all done.
You async function func also returns a promise so you need the await keyword before its call.
for(let i = 0; i < 3 ; i++){
await func(callback,i);
}

Using javascript's Symbol.asyncIterator with for await of loop

I am trying to understand javascript's Symbol.asyncIterator and for await of. I wrote some simple code and it throws an error saying:
TypeError: undefined is not a function
on the line which tries to use for await (let x of a).
I could not understand the reason for it.
let a = {}
function test() {
for(let i=0; i < 10; i++) {
if(i > 5) {
return Promise.resolve(`Greater than 5: (${i})`)
}else {
return Promise.resolve(`Less than 5: (${i})`)
}
}
}
a[Symbol.asyncIterator] = test;
async function main() {
for await (let x of a) { // LINE THAT THROWS AN ERROR
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
I create an empty object a and insert a key Symbol.asyncIterator on the same object and assign it a function named test that returns a Promise. Then I use for await of loop to iterate over all the values that the function would return.
What am I doing incorrectly?
PS: I am on the Node version 10.13.0 and on the latest version of Chrome
To be a valid asyncIterator, your test function must return an object with a next method that returns a promise of a result object with value and done properties. (Technically, value is optional if its value would be undefined and done is optional if its value would be false, but...)
You can do that in a few ways:
Completely manually (awkward, particularly if you want the right prototype)
Half-manually (slightly less awkward, but still awkward to get the right prototype)
Using an async generator function (simplest)
You can do it completely manually (this doesn't try to get the right prototype):
function test() {
let i = -1;
return {
next() {
++i;
if (i >= 10) {
return Promise.resolve({
value: undefined,
done: true
});
}
return Promise.resolve({
value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
done: false
});
}
};
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
You can do it half-manually writing a function that returns an object with an async next method (still doesn't try to get the right prototype):
function test() {
let i = -1;
return {
async next() {
++i;
if (i >= 10) {
return {
value: undefined,
done: true
};
}
return {
value: i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`,
done: false
};
}
};
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
Or you can just use an async generator function (easiest, and automatically gets the right prototype):
async function* test() {
for (let i = 0; i < 10; ++i) {
yield i > 5 ? `Greater than 5: (${i})` : `Less than 5: (${i})`;
}
}
let a = {
[Symbol.asyncIterator]: test
};
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
About prototypes: All async iterators you get from the JavaScript runtime itself inherit from a prototype that provides the very basic feature of ensuring the iterator is also iterable (by having Symbol.iterator be a function returning this). There's no publicly-available identifer or property for that prototype, you have to jump through hoops to get it:
const asyncIteratorPrototype =
Object.getPrototypeOf(
Object.getPrototypeOf(
async function*(){}.prototype
)
);
Then you'd use that as the prototype of the object with the next method that you're returning:
return Object.assign(Object.create(asyncIteratorPrototype), {
next() {
// ...
}
});
The test function must not return a promise, but an Iterator (an object with a next() ) method, that method then has to return a Promise (which makes it an async iterator) and that Promise has to resolve to an object containing a value and a done key:
function test() {
return {
next() {
return Promise.resolve({ value: "test", done: false });
}
};
}
Now while that works, it is not that useful yet. You could however create the same behaviour with an async generator function:
async function* test() {
await Promise.resolve();
yield "test";
}
Or in your case:
async function* test() {
for(let i = 0; i < 10; i++) {
if(i > 5) {
await Promise.resolve();
yield `Greater than 5: (${i})`;
}else {
await Promise.resolve();
yield `Less than 5: (${i})`;
}
}
}
You should make test an async generator function instead, and yield instead of return:
let a = {}
async function* test() {
for(let i=0; i < 10; i++) {
if(i > 5) {
yield Promise.resolve(`Greater than 5: (${i})`)
}else {
yield Promise.resolve(`Less than 5: (${i})`)
}
}
}
a[Symbol.asyncIterator] = test;
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
It looks like the test function needs to be async so that the x in the for await gets unwrapped, even though test doesn't await anywhere, otherwise the x will be a Promise that resolves to the value, not the value itself.
yielding Promise.resolve inside an async generator is odd, though - unless you want the result to be a Promise (which would require an extra await inside the for await loop), it'll make more sense to await inside the async generator, and then yield the result.
const delay = ms => new Promise(res => setTimeout(res, ms));
let a = {}
async function* test() {
for(let i=0; i < 10; i++) {
await delay(500);
if(i > 5) {
yield `Greater than 5: (${i})`;
}else {
yield `Less than 5: (${i})`;
}
}
}
a[Symbol.asyncIterator] = test;
async function main() {
for await (let x of a) {
console.log(x)
}
}
main()
.then(r => console.log(r))
.catch(err => console.log(err))
If you didn't make test a generator, test would have to return an iterator (an object with a value property and a next function).

Output results of two promises into a single object

I have two asynchronous functions which create promises. Both functions use the same input i.
async function1(i) {}
async function2(i) {}
I will be calling these functions multiple times with different values for my input, and I want to make my code as efficient as possible, so I want to queue the promises and have them run in parallel using Promise.all().
However, I want to get a single result as my final output, which will be an array of objects like so:
[
{
input: i,
result1: result1,
result2: result2
},
...
]
I have accomplished this in two descrete steps:
async function function1(i) {
return i * i
}
async function function2(i) {
return i * i * i
}
async function main() {
var promises = []
for (let i = 0; i < 10; i++) {
let promise = function1(i)
.then(function(result1) {
return {i:i, result1:result1}
});
promises.push(promise)
}
var final = await Promise.all(promises)
var promises2 = [];
for (let i = 0; i < 10; i++) {
let promise = function2(i)
.then (function(result2) {
final[i]['result2'] = result2;
});
promises2.push(promise);
}
await Promise.all(promises2)
console.log(final)
}
main()
However, I feel like this can be accomplished using a single Promise.all(). Can you tell me how?
async function function1(i)
{
return i * i
}
async function function2(i)
{
return i * i * i
}
async function main()
{
const promises = [];
for (let i = 0; i < 10; i++)
promises.push(function1(i), function2(i));
const results = await Promise.all(promises);
const data = [];
for (let i = 0; i < 10; i++)
{
const [result1, result2] = results.slice(i * 2, i * 2 + 2);
data.push({ i, result1, result2 });
}
console.log(data);
}
main();
This should work smoothly and quickly. The functions function1 and function2 return Promises if you do not await them, so pushing them onto the promises array is self-explanatory.
Then you await Promise.all, which waits until all 20 promises that were fired off have completed. Finally, the second loop runs through the promises that were returned.
In my code I used destructuring assignments. I assume those are available to you since you are using async functions, which implies that you can use ES2017.
EDIT: 333's answer is correct, not mine. This solution will have 2 batches in the queue.
I think I figured it out:
console.log("start")
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function function1(i) {
await sleep(2000);
return i * i
}
async function function2(i) {
await sleep(2000);
return i * i * i
}
async function main() {
var promises = []
for (let i = 0; i < 10; i++) {
let a = function1(i);
let b = function2(i);
let promise = Promise.all([a,b]).then(
function([resulta,resultb]) {
return {i:i, result1: resulta, result2: resultb}
});
promises.push(promise)
}
var final = await Promise.all(promises)
console.log(final)
}
main()
Note that I added a sleep function to test the parallelization of these functions. Everything runs in 2 seconds, so I think it is optimized.

Categories

Resources