How to get rid of async in function? - javascript

Let's say I have this code:
const myFunction = async => {
const result = await foobar()
}
const foobar = async () => {
const result = {}
result.foo = await foo()
result.bar = await bar()
return result
}
And I want this:
const myFunction = () => {
const result = foobar()
}
I tried to wrap foobar like this:
const foobar = async () => {
return (async () => {
const result = {}
result.foo = await foo()
result.bar = await bar()
return result
})()
}
But this still return a promise
I can't use .then in myFunction, I need that foobar returns the result variable instead a promise.
The problem is that myFunction is an async function and it will return a promise but It should return undefine I need to get rid of async in myFunction.
Edit: as Sebastian Speitel said, I want to convert myFunction to sync
Edit 2: to Shilly, I am using nightwatch for end2end test, nightwatch will call myFunction() if there are no errors in the execution of the function it will run perfectly, if there's an error then nightwatch's virtual machines will run forever instead stop, this problem happens if the called function is async.

To change an asynchronous function into a normal synchronous function you simply have to drop the async keyword and as a result all await keywords within that function.
const myFunction = async () => {
const result = await foobar();
// ...
return 'value';
};
// becomes
const myFunction = () => {
const result = foobar();
// ...
return 'value';
};
You should however keep one simple rule in mind.
You can't change a asynchronous function into a synchronous function if the return value depends on the value(s) of the resolved promise(s).
This means that functions that handle promises inside their body, but from whom the return value doesn't depend on those resolved promises are perfectly fine as synchronous functions. In most other scenarios you can't drop the asynchronous behaviour.
The following code gives you an example for your situation, assuming the return value of myFunction doesn't depend on the resolved promise.
const myFunction = () => {
const result = foobar();
result.then(data => doSomethingElse(data))
.catch(error => console.error(error));
return 'some value not dependent on the promise result';
};
If you want to learn more about promises I suggest checking out the promises guide and the async/await page.

Have you looked into using .executeAsync() and then having the promise call the .done() callback? That way it should be possible to wrap foobar and just keep either the async or any .then() calls inside that wrapper.
My nightwatch knowledge is very stale, but maybe something like:
() => {
client.executeAsync(( data, done ) => {
const result = await foobar();
done( result );
});
};
or:
() => {
client.executeAsync(( data, done ) => foobar().then( result => done( result )));
};

Any function marked with async will return a Promise. This:
const foobar = async () => {
return 7;
}
Will a return a Promise of 7. This is completely independent of wether the function that calls foobar is async or not, or uses await or not when calling it.
So, you're problem is not (only) with myFunction: is foobar using async which forces it to always return a Promise.
Now, said that, you probably can't achieve what you want. Async-Await is only syntax sugar for promises. What you're trying is to return a synchronous value from an asynchronous operation, and this is basically forbidden in javascript.

You're missing very important understanding here between the synchronous and asynchronous nature of the code.
Not every async function can be converted to synchronous function. You can use callback pattern instead of await/async, but I doubt that would be useful to you.
Instead I would recommend you just use await, as in your first code example, and leave functions as async, it shouldn't harm your logic.

Check this out
function foo(){
return 'foo'
}
function bar(){
return 'bar'
}
const foobar = () => {
return new Promise((resolve)=>{
let result = {}
result.foo = foo()
result.bar = bar()
return resolve(result)
})
}
const myFunction = () => {
const result = foobar()
let response = {}
result.then(val=>{
response = Object.assign({}, val);
return response
});
}
var test = myFunction()
console.log(test)

Related

Awaiting to a normal function

Is it possible await to a function that is not a promise?
Maybe a function that cannot fail.
for example:
async function doWork() {
const newData = await cannotFail();
console.log("done: "+ newData);
}
function cannotFail() {
var data = //cannot fail code . . .
return data;
}
doWork();
I was thinking maybe with another syntax this option makes sense.
Consider these two examples
async function getData(){
return "some data";
}
async function doSomething() {
const data = await getData();
console.log(data);
}
doSomething()
function getData(){
return "some data";
}
async function doSomething(){
const data = getData();
console.log(data);
}
doSomething();
The result is exactly the same. You only use await when you want to wait for an asnyc function like it is synchronous. Normal functions already are synchronous.
And yes it is possible to use await on a normal function
function getData(){
return 'some data';
}
async function doSomething(){
const data = await getData();
console.log(data);
}
doSomething();
There is just no reason to.
It is possible to use await with an expression that does not evaluate to a promise. Whether that is useful, is questionable.
First of all, when await is followed by an expression that does not evaluate to a promise object, it is turned into one -- a resolved promise.
The main difference you get by using await with a non-promise or a resolved promise, is that await will make the async function return. This behaviour is not dependent on whether the promise is already resolved or not. await always postpones the further execution of the function by placing that resuming-job on the promise job queue.
See the difference here:
async function test() {
let a = 1; // Without await
console.log(a);
return 2;
}
test().then(console.log);
console.log("end of main, synchronous code");
And with await
async function test() {
let a = await 1; // With await
console.log(a);
return 2;
}
test().then(console.log);
console.log("end of main, synchronous code");
Note the different order of execution.
It's not necessary, but it is possible:
const newData = await Promise.resolve( cannotFail() );

How to assign variable to result of asynchronous class method that returns an object in its promise?

Looks nobody on internet describes similar problem, and similar solution is not working for me.
I am trying to scrape webpage so I created class for parser and one of the method looks like follows:
get chListUrl() {
return "http://www.teleman.pl/program-tv/stacje";
}
getChannels() {
var dict = {};
axios.get(this.chListUrl).then(function (response) {
var $ = cheerio.load(response.data);
var ile_jest_stacji = $('#stations-index a').length;
$('#stations-index a').each( (i,elem) => {
let href = $(elem).attr('href');
let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');
let nazwastacji = $(elem).text();
dict[nazwastacji]=kodstacji;
});
return dict;
}).catch(function (error) {
console.log(error);
return null;
}).finally(function() {
console.log("Koniec");
});
}
And problem is getChannels must be indirectly asynchronous because it contains axios BUT
let tm = new TM();
var a = tm.getChannels();
a is always undefined and it should be dictionary! Such construct means "assing to variable a result of execution of tm.getChannels()" so assignment should always be done AFTER whole function ends. Otherwise such syntax in language is useless because you will never be sure what value is stored in variable, and such errors are difficult to find and debug.
var a = await tm.getChannels();
NOT WORKING -> SyntaxError: await is only valid in async function (huh?)
adding async to getChannels() changes nothing.
Assing async to getChannels() and remove 'await' from assignment returns Promise{undefined} (huh?)
putting async before axios changes nothing as response is already handled by .then()
changing return dict to return await dict gives another "await is only valid in async function" (huh? axios is asynchronous)
I'm scratching my head over this for 2 weeks.
In Swift when something is return in completion handler it is assigned to variable in proper moment, why something returned by Promise not works the same way?
You need to be inside an async function to use the await expression:
The await operator is used to wait for a Promise. It can only be used inside an async function.
await operator on MDN
Example sourced from MDN:
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
Fixing your issue
class TM {
get chListUrl() {
return "http://www.teleman.pl/program-tv/stacje";
}
async getChannels() { // you need not use get syntax
let dict = {};
try { // we will be handling possible errors with try catch instead of reject
const response = await axios.get(this.chListUrl);
let $ = cheerio.load(response.data);
let ile_jest_stacji = $('#stations-index a').length;
$('#stations-index a').each( (i,elem) => {
let href = $(elem).attr('href');
let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');
let nazwastacji = $(elem).text();
dict[nazwastacji]=kodstacji;
});
return dict;
} catch(ex) {
console.log(ex);
return null
}
}
}
// let's make it work!
(async function() {
const tm = new TM()
const channels = await tm.getChannels()
// do whatever you want with channels
console.log(channels)
})()
Now, you're probably not going to call getChannels out of nowhere like this instead you will probably be inside a function that you yourself defined, you need to add the async keyword to this function. Whatever block function your code is in needs to be async.
If you want to use the async/await syntax you should remove the .then() syntax and you can resolve that way:
async getChannels() {
const response = await axios.get(this.chListUrl);
return response
}
You can learn more about async/await in the link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

JavaScript Async/Await console.log() on array returns empty

Hello Stack Overflow community,
I come to you with a problem related to JS async/await. I am trying to call an async function and then log the array to where the async function pushes the results to the console. If I call it like so directly in the console:
console.log(Page.data) - I can see that it has results in it, but if it is called on click of a button it logs an empty array.
// It is a nested object so do not worry if you don't exactly understand where Page.data comes from
Page.data = []
async function f1() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function f2() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function f3() {
// Fetch JSON data
// Process data
// Pushes at some point to the Page.data array
}
async function load(loader) {
let fn = async function() {};
if(condition1) fn = f1;
else if(condition2) fn = f2;
else fn = f3;
// This is the line that makes me problems
// According to documentation async functions return a promise
// So why would the array in the case be empty?
// Since I am telling it to display after the function is done
await fn(loader).then(console.log(Page.data))
}
This is just a template of my code and logic. I hope that you can understand where I am going.
Your help will be much appreciated.
The await expression causes async function execution to pause until a Promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise.
For instance (this is an MDN example with some added comments):
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
// note that here, you are "awaiting" the RESOLVED RESULT of the promise.
// there is no need to "then" it.
var x = await resolveAfter2Seconds(10);
// the promise has now already returned a rejection or the resolved value.
console.log(x); // 10
}
f1();
So you would "await" your function, which would hold up the execution until the promise either resolves or rejects. After that line, you would run your console.log, and it would log as expected. Short answer, "remove the then".
I should add, if the result of the "awaited" function is not a promise, it is converted to a promise (so technically, there is no need to return a promise, it'll wrap up your returned value for you).
the problem is that you can use then with await for the same method, lets check some examples provided by MDN:
this is a working Promise using async/await:
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!");
}, 250)
})
const functionCaller = async() => {
const result = await myFirstPromise
console.log("the result: ", result);
}
functionCaller();
what you are trying is:
let myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!");
}, 250)
})
const functionCaller = async() => {
// you are not returning anything here... actually you are not doing anything with the response. despite it shows something, it is not sending any response
await myFirstPromise.then(console.log("something happened"))
}
// then this function doesn't really get a value.
functionCaller();
so what you need to do in your load call, is to change it like this:
async function load(loader) {
let fn = async function() {};
if(condition1) fn = f1;
else if(condition2) fn = f2;
else fn = f3;
return await fn(loader)
}

Why do I need to async/await again in a different function?

I'm confused of why do I need to run the async/await again in another function
Example
async function fetchData() {
try {
const result = await axios.get('http://example.com')
return result
} catch(err) {
return err
}
}
// and in another function I need to async await again
// if I want to get the value of fetchData()
// or else it will return pending promise object
function mapData() {
const data = fetchData()
console.log(data) // is a Pending Promise
}
If I want to get the data instead of Promise object
async function mapData() {
const data = await fetchData() // I still need to await??
console.log(data) // real value
}
I thought that If I already async/await in fetchData function it's already return a value instead of promise, why do I need to async/await again to get the actual data in mapData function?
An async function will always return a Promise - a Promise that resolves once the async function reaches its end (after any possible containing awaits). It doesn't magically make asynchronous code synchronous; any consumers of an async function will have to deal with its asynchronity as well.
It also usually makes more sense to handle errors in the consumer. Here, it doesn't look like you're doing anything special with the error in fetchData, so you can return the Promise immediately, without having to await it in the downstream function:
function fetchData() {
return axios.get('http://example.com');
}
async function mapData() {
try {
const data = await fetchData()
console.log(data)
} catch(e) {
console.log('Something went wrong...');
// handle failure of fetchData
}
}
Promises deal with time. They are a wrapper for a value that will be available eventually, BUT NOT YET. And you don't freeze your entire app untill the value is avilable.
async/await is just syntactic sugar over Promises. It lets you write code like
async function myFunction(){
var id = await asyncMethod1();
var value = await asyncMethod2(id);
return syncMethod3(id, value);
}
instead of
function myFunction(){
return asyncMethod1().then(id => asyncMethod2(id).then(value => syncMethod3(id, value)));
}
but it doesn't change how this thing works underneath.
So although syncMethod3 is sync the returned value still relies on the asyncronously computed values foo and bar. which makes myfunction async.
And every function that calls myFunction needs to wait untill myFunction has computed its value, ... and so on.

'await' is not working in async function

The code below gives me the following error:
SyntaxError: await is only valid in async function
async function getLastTransaction()
{
paymentsApi.listPayments(locationId, opts).then(function(transactions)
{
if(transactions[transactions.length-1] === undefined)
return; //no new transaction yet
var last_transaction_id = transactions[transactions.length-1].id;
var last_transaction_in_queue;
try {
last_transaction_in_queue = JSON.parse(order_queue[0]).order_id;
} catch (e) {
last_transaction_in_queue = order_queue[0].order_id;
}
//check if latest transaction is the same as lastest transaction in queue
if(last_transaction_id !== last_transaction_in_queue) {
console.log(`new payment...`);
var obj = await createTransactionObject(transactions[transactions.length-1], () => {
order_queue.unshift(obj);
console.log('new added', order_queue);
});
}
I don't understand the error since I'm using await for the same function createTransactionObject() but in another piece of code.
For example, in the following code, I don't get the error, and still, I'm using await before createTransactionObject()
async function populateQueue(transaction_list) {
for(var i = 0; i < transaction_list.length; i++)
{
var transaction_json = await createTransactionObject(transaction_list[i], () => {});
order_queue.unshift(transaction_json);
} }
You need to change this line:
paymentsApi.listPayments(locationId, opts).then(function(transactions)
to this:
paymentsApi.listPayments(locationId, opts).then(async (transactions) =>
The anonymous function you supply to .then needs to be asynced, because you're using await in it.
You could also replace the line with this (maybe even better):
const transactions = await paymentsApi.listPayments(locationId, opts);
Because the getLastTransaction function is asynced.
First of all you get the error not because the getLastTransaction function is async but because the anonymous function .then(function(transactions) is not async and you use await inside of it. You can't do that.
Now note that simple redeclaring the function as async function(transactions) will be syntactically correct but will that work fine? What happens now is that getLastTransaction fires some async process in the background and never awaits the result. Is that what you want?
To fix that you have to ask yourself: what am I trying to achieve? Should getLastTransaction wait for whatever the inner function is doing? Then make use of that async declaration:
async function getLastTransaction() {
const transactions = await paymentsApi.listPayments(locationId, opts);
// Some other code here
return xyz;
}
This is under the assumption that the paymentsApi is async/await compatible. If it is not then you have to play with manually creating and returning Promise objects (in which case async declaration won't help much).
paymentsApi.listPayments(locationId, opts).then(function(transactions) should be
paymentsApi.listPayments(locationId, opts).then(async function(transactions) as await can only be used in an asynchronous function.
Better still, since you already have an async function at the top level, why don't you just await paymentsApi.listPayments(locationId, opts) instead of chaining it with a then?
async function getLastTransaction() {
const transactions = await paymentsApi.listPayments(locationId, opts);
// Do something with transactions
}
await keyword works when scope is having async keyword used, here .then accepts callback function that doesn't have async, so await becomes alien here.
Lets re-write your code in async-await style:
async function getLastTransaction()
{
// #1 this fixes to adopt the await style and fixes the problem
const transactions = await paymentsApi.listPayments(locationId, opts);
// your rest code goes here ...
if(last_transaction_id !== last_transaction_in_queue) {
//now do it like this, await will make sense now
const obj = await createTransactionObject(transactions[transactions.length-1]);
order_queue.unshift(obj);
}
}

Categories

Resources