JS Promise: control flow - javascript

I have to set a few things up via an API. It's important that the different functions are executed after each other. All of the listed functions return a proper promise.
a(analyticsConfig._listConfig)
.then(function() {
return b(listName, analyticsConfig._fieldConfig);
})
.then(function() {
return c(listName)
})
.then(function() {
return d(analyticsConfig._roleConfig);
})
I'd like to use something like a.then(b(listName, analyticsConfig._fieldConfig)) or so but as you probably know this won't work.
Is there another way to do this?

That will only work if b returns a function that returns a promise. You always must pass a function to then as the callback, there's no way around that. There are however many ways to construct one.
Leaving partial application (with bind or other), currying and such stuff aside, your best options for nicer syntax are ES8 async/await
(async function() {
await a(analyticsConfig._listConfig);
await b(listName, analyticsConfig._fieldConfig);
await c(listName);
await d(analyticsConfig._roleConfig);
})();
or ES6 arrow functions:
a(analyticsConfig._listConfig)
.then(() => b(listName, analyticsConfig._fieldConfig))
.then(() => c(listName))
.then(() => d(analyticsConfig._roleConfig))

You can write it as
a.then(b.bind(null, listName, analyticsConfig._fieldConfig))
or, if you're either using babel to transpile your code, or you're targeting a version of node > v4., you can do
a.then(() => b(listName, analyticsConfig._fieldConfig))

You can bind it:
a.then(b.bind(context,listName,analyticsConfig._fieldConfig))
Be sure to bind the expected context to it though.
According to the docs:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

You can do the following using async/await:
function a() {
console.log('Getting A...');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello A!');
}, 1000);
});
}
function b() {
console.log('Getting B...');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello B!');
}, 1000);
});
}
function c() {
console.log('Getting C...');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello C!');
}, 1000);
});
}
function d() {
console.log('Getting D...');
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello D!');
}, 1000);
});
}
async function getAll() {
await a();
await b();
await c();
await d();
console.log('Done');
}

Related

JS Promise function call that returns object [duplicate]

This question already has answers here:
await setTimeout is not synchronously waiting
(2 answers)
Closed last month.
I have a async fetch function that waits 2 seconds and returns a object:
async function fetch() {
var object;
await setTimeout(() => { object = { name: 'User', data: 'API Data' } }, 2000);
return object;
}
I want to display the object when the initialization is completely done (after 2 seconds)
fetch().then((val) => {
console.log("DONE!");
console.log(val.name);
}).catch((err) => {
console.log("ERROR!");
console.log(err);
});
The code prints both DONE and ERROR Cannot read properties of undefined (reading 'name')
I have tried with Promise, no luck
let promise = new Promise((resolve, reject) => {
let request = fetch();
if (request !== undefined)
resolve(request);
else
reject(request);
}).then((val) => {
console.log(val);
});
How can I properly check that fetch() has returned a value before printing without changing the inside of the function. I can delete the async and await in it but I am unable to edit it (I.E. adding a Promise inside)
Based on requirement
I can delete the async and await in it (fetch function) but I am unable to edit it (I.E. adding a Promise inside)
The only way I see is to override window.setTimeout function to make it to return a promise. That way you will be able to await it and there will be no need to modify your fetch function.
const oldTimeout = window.setTimeout;
window.setTimeout = (fn, ms) => {
return new Promise((resolve, reject) => {
oldTimeout(() => {
fn();
resolve();
}, ms);
});
};
async function fetch() {
var object;
await setTimeout(() => {
object = { name: "User", data: "API Data" };
}, 2000);
return object;
}
fetch()
.then((val) => {
console.log("DONE!");
console.log(val.name);
})
.catch((err) => {
console.log("ERROR!");
console.log(err);
});
NOTE: For anyone without this requirement - please, use other answers to this question or check await setTimeout is not synchronously waiting for additional details/explanations. This kind of overridings are very confusing due to everyone expect common and well-known functions to behavior in a way described in the docs.
You cannot await the setTimeout function, this is because your function returns undefined. You have used the promise in the wrong way. Below code will fix your issue.
function fetch() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: "User", data: "API Data" });
}, 2000);
});
}
fetch()
.then((val) => {
console.log("DONE!");
console.log(val.name);
})
.catch((err) => {
console.log("ERROR!");
console.log(err);
});
And remember that there is no need to change the setTimeout function.
The problem is that setTimeout does not actually return a promise, which means you cannot use await with setTimeout, that's why the var object; is returned instantly as undefined.
To solve this issue, you simply need to wrap setTimeout around a promise.
Like so:
function setTImeoutAwait(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
You can then use it like this:
async function fetch() {
var object;
await setTImeoutAwait(1000).then(() => {
object = { name: "test" };
});
return object;
}

Traditional way of doing asnyc method in javascript

I was searching online on how we create the traditional way of doing async function in Javascript but it wasn't available. I have implemented a promise function in my program, however the software that I am using (tableu) to create all custom styling does not support ES5-ES8 and async functions, as this will throw an error, so I was wondering if this is possible.
function promise() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 500);
})
}
async function result() {
await promise();
}
result().then(render => {
customStyle()
});
All of my code shown is working fine. I'm wondering how can I convert this to the old way of doing async functions. Is this possible or is it only available in ES8?
Callbacks are the non-Promise or async/await way of doing this, and are basically how those things work under the hood.
Here's a simple example by modifying your snippet:
function promise(callback) {
setTimeout(() => callback(), 500);
}
function result() {
promise(callback);
}
function callback() {
customStyle();
};
Instead of result being an async function that you can await elsewhere in your code, it could also take a callback argument, like promise, that you would pass it when it's invoked. The implementation of that callback function would be like the then of an actual Promise.
Now you can see why the Promise API and async/await were such nice improvements to the spec.
To use promises the tradicional way, you have to replace the await and use .then(()=> ...). I'll try to show a snippet here to help you to understood.
The code that you have shown does not need the async or await, it goes well like that
function promise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('resolved')
resolve()
}, 500);
})
}
promise().then(render => {
customStyle()
});
Here i'll show you a code that have a good use of it and then I'll convert it:
function callSomeService() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called')
resolve({ idOfSomething: 1 })
}, 2000);
})
}
function callAnotherServiceUsingTheDataOfThePreviousCall(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called with', data)
resolve(['potato 1', 'potato 2', 'potato 3'])
}, 2000);
})
}
async function result() {
const serviceResponse = await callSomeService();
const arrayOfPotatos = await callAnotherServiceUsingTheDataOfThePreviousCall(serviceResponse);
return arrayOfPotatos.map((potato, index) => `${index} - ${potato}`)
}
result().then(arrayOfPotatos => {
arrayOfPotatos.forEach(potato => console.log(potato))
});
Now I'll convert it to not use async or await, but still using promises.
function callSomeService() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called')
resolve({ idOfSomething: 1 })
}, 2000)
})
}
function callAnotherServiceUsingTheDataOfThePreviousCall(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('service whas called with', data)
resolve(['potato 1', 'potato 2', 'potato 3'])
}, 2000)
})
}
function result() {
return callSomeService().then(serviceResponse => {
return callAnotherServiceUsingTheDataOfThePreviousCall(
serviceResponse
).then(arrayOfPotatos => {
return arrayOfPotatos.map((potato, index) => `${index} - ${potato}`)
})
})
}
result().then(arrayOfPotatos => {
arrayOfPotatos.forEach(potato => console.log(potato))
})
Those two last codes does the same thing, but the second use async and await and the third does not. Async and await are just a syntax sugar to use promises.
I expect that will help you.

Simple async await question with function returns

I have a simple yet perplexing issue with async functions.
I wish to simply return the value when its ready from the function.
Here is a sample code:
async function test() {
setTimeout(function() {
return 'eeeee';
}, 5000);
}
test().then(x => {
console.log(x)
});
You will get undefined been logged at once.
It's clear that you are trying to write a sleep() async function, but do remember that setTimeout is a sync function calling with a callback function will be executed at a given time, so while you are executing test(), the calling will run to end and return undefined as you have no return statement in the function body, which will be passed to your .then() function.
The right way to do this is to return a Promise that will be resolved after a given time, that will continue the then call.
async function sleep(time){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("echo str")
},time)
})
}
sleep(5000).then((echo) => console.log(echo))
sleep function in short
const sleep = async time => new Promise(resolve=>setTimout(resolve,time))
With Promises
const setTimer = (duration) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done!');
}, duration);
});
return promise;
};
setTimer(2000).then((res) => console.log(res));
An async function has to return a promise. So to fix this, you can wrap your setTimeout function in a new promise like so:
async function test(){
return await new Promise((resolve, reject) => {
setTimeout(function(){
resolve('eeeee');
},5000);
})
}
test().then(x => {
console.log(x)
});
You can learn more about async/await on the MDN docs here. Hope this helps!

Is it possible Async Await - Fluent builder approach

This my road of growing up: callbacks, promises, async/await. I keep in mind a pattern - fluent builder that looks more to interpreter. I would like to mix async/await with interpreter. Is it possible? I feel that it is not possible. But I can define why exactly.
I have:
after(async () => {
await shellContainer.uninstall()
await shellContainer.dispose()
})
I am interesting in:
after(async () => {
await shellContainer
.uninstall()
.dispose()
})
Regards.
To separate concerns, you could introduce a dedicated builder which implements the fluent interface.
With that you only need to return a promise from the final build method, making things a lot simpler.
The following is a rather crude but functional example:
class ShellContainer
{
uninstall() {
return new Promise(resolve => {
setTimeout(() => {
console.log('uninstalled');
resolve();
}, 400 + Math.random() * 600);
});
}
dispose() {
return new Promise(resolve => {
setTimeout(() => {
console.log('disposed');
resolve();
}, 400 + Math.random() * 600);
});
}
}
class ShellContainerBuilder
{
container;
plan;
constructor() {
this.reset();
}
reset() {
this.container = new ShellContainer();
this.plan = () => Promise.resolve();
}
stage(op) {
this.plan = ((prev) => () => prev().then(op))(this.plan);
}
uninstall() {
this.stage(() => this.container.uninstall());
return this;
}
dispose() {
this.stage(() => this.container.dispose());
return this;
}
build() {
return this.plan().then(() => this.container);
}
}
(async () => {
console.log('starting w/o builder:');
const shellContainer1 = new ShellContainer();
await shellContainer1.uninstall();
await shellContainer1.dispose();
console.log('w/o builder done.');
console.log('starting w/ builder:');
const shellContainer2 = await (new ShellContainerBuilder()).uninstall().dispose().build();
console.log(shellContainer2);
console.log('w/ builder done.');
})();
If you change .uninstall to return the instance (shellContainer) while assigning its Promise to a property of the instance, and retrieving that Promise in the chained call, yes, it's possible:
class ShellContainer {
uninstall() {
// Chain or construct a Promise and assign the result to a property of the instance:
this.uninstProm = new Promise((resolve, reject) => {
// do stuff
});
return this;
}
dispose() {
return this.uninstProm.then(() => {
// do stuff
});
}
}
and then,
await shellContainer
.uninstall()
.dispose()
will resolve once dispose finishes.
Note that with this approach, calling uninstall by itself may result in unexpected behavior, since .uninsall will be returning the instance synchronously, rather than the Promise. You might consider an extra argument or something to indicate whether you want to chain the uninstall call with something else, or whether you want the Promise to be returned directly, perhaps something like
class ShellContainer {
uninstall(doChain) {
// Chain or construct a Promise and assign the result to a property of the instance:
this.uninstProm = new Promise((resolve, reject) => {
// do stuff
});
return doChain ? this : this.uninstProm;
}
dispose() {
return this.uninstProm.then(() => {
// do stuff
});
}
}
and
await shellContainer
.uninstall(true)
.dispose()
or just
await shellContainer.uninstall(); // no doChain argument
But if there's only going to be one Promise, there's not much need for await in many cases - it may not make the code clearer at all. For example
after(async () => {
await shellContainer
.uninstall()
.dispose()
})
is equivalent to
after(() => shellContainer
.uninstall()
.dispose()
);
The pattern - Interpreter that implements Fluent builder is not suitable for Async/Await. Because await is applied per an operation. There is not such syntax to process async in the middle of the chain. To handle async operations you should split chaining and wrap the operations by await operator like it is at the first code snippet.

Understanding Promise and Await

I am just trying to understand how Promises and Async-Await work.
I want this to resolve by logging 1, 2, 3 in that order. Currently it logs 1, 3, 2.
I know the Promise doesn't really make sense here but in my program it has other uses so that needs to stay. The route from Caller function to Test also needs to stay (If need be you can change these but just know that they are there for a reason)
My question is how do I wait for the Caller function to resolve?
Here is my code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
Test();
}
console.log('1');
Caller();
console.log('3');
I have tried what I understand, which is to make the Caller() function await the Test Promise, but that of course makes the Caller() function async and therefore we still get 1, 3, 2
async function Caller() {
await Test();
}
Is there maybe some way to use await without making the function async?
You can only await a function that returns a promise (well, not quite true, if it doesn't return a promise it creates a promise that resolves instantly)
You can only await when you are inside an asynchronous function
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
async function caller() {
console.log('1');
await test();
console.log('3 (this is blocked awaiting the promise');
}
caller()
console.log("This is not blocked because caller is async");
This is a very straightforward, simple way of doing what you ask.
The await keyword can only be used inside functions
defined with async.
function test(ms) {
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
async function caller() {
console.log(1, ' - caller() started');
await test(2000).then(() => {
console.log(2, ' - test() resolved')
});
console.log(3, ' - delayed until "test()" has resolved');
return 4;
}
// wait for "caller()" to resolve
caller().then((result) => {
console.log(result, " - caller() finished")
});
console.log(5);
Here's a good article by Google which expands on the subject:
Async functions - making promises friendly.
Cite source.
here is how you could use functions like this:
function sleep(ms) {
return new Promise(r => {
setTimeout(() => r(), ms);
});
}
(async () => {
console.log(1);
await sleep(1000); // 1s
console.log(2);
await sleep(2000) // 2s
console.log(3)
})();
The previous answers are all correct but I just feel like this answer makes more sense. It is more accurate to the original question's code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
return Test();
}
(async() => {
console.log('1');
await Caller();
console.log('3');
})();

Categories