Awaiting to a normal function - javascript

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

Related

how to turn try catch function into promise and use promise.all

In Reactjs, I have two try-catch functions listed as below, and I need to wrap them into a promise.all function. Could anyone tell me how please? I know first I have to turn those two functions into promise, but how?
function one(){
let isValid = true;
...
if(isValid){
try{
const response = await AA.sendMsg({XX})
return response
}catch(e){
console.log(e)
}
}
}
function two(){
let isValid = true;
...
if(isValid){
try{
const response = await BB.sendMsg({YY})
return response
}catch(e){
console.log(e)
}
}
}
sendMsg already returns a Promise (at least, it should, if it doesn't then it makes no sense to use await or introduce Promises).
Wrapping then in extra Promises would be an anti-pattern. Don't do that.
Just pass them to Promise.all:
const [responseAA, responseBB] = await Promise.all([AA.sendMsg(...), BB.sendMsg(...)]);
await is only available if you declare your function as async.
Given that, invoking them will give you a promise without extra work.
so just do:
const result = await Promise.all([one(), two()])

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

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.

How to get rid of async in function?

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)

'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