Call An Asynchronous Javascript Function Synchronously
Asked Answered
R

15

339

First, this is a very specific case of doing it the wrong way on-purpose to retrofit an asynchronous call into a very synchronous codebase that is many thousands of lines long and time doesn't currently afford the ability to make the changes to "do it right." It hurts every fiber of my being, but reality and ideals often do not mesh. I know this sucks.

OK, that out of the way, how do I make it so that I could:

function doSomething() {

  var data;

  function callBack(d) {
    data = d;
  }

  myAsynchronousCall(param1, callBack);

  // block here and return data when the callback is finished
  return data;
}

The examples (or lack thereof) all use libraries and/or compilers, both of which are not viable for this solution. I need a concrete example of how to make it block (e.g. NOT leave the doSomething function until the callback is called) WITHOUT freezing the UI. If such a thing is possible in JS.

Renettarenew answered 3/2, 2012 at 0:3 Comment(13)
It's simply not possible to make a browser block and wait. They just won't do it.Byebye
javascript dosent having blocking mechanisms on most browsers...you'll want to create a callback that is called when the async call finishes to return the dataOriginality
I don't think this can be done. Javascript (web workers notwithstanding) is singlethreaded - the callback can't be called until the current event handler returns. This would require the equivalent of the C# async/await feature in Javascript and I doubt such a beast exists. I'm afraid you're stuck rewriting your code into CPS, as annoying as that is.Rizal
You're asking for a way to tell the browser "I know I just told you to run that previous function asynchronously, but I didn't really mean it!". Why would you even expect that to be possible?Ingather
Thanks Dan for the edit. I wasn't strictly being rude, but your wording is better.Renettarenew
@lwburk it's possible in c#, but the reasons why don't apply in js because the infrastructure isn't there in js to do it. I was basically confirming it can't be done.Renettarenew
@Inerdial it's not annoying, it's quite nice, but time constraints for this aspect of the refactoring don't permit it right now; it'll happen later as part of a larger refactoring.Renettarenew
Possible duplicate: #10652255Blida
@RobertC.Barth It's now possible with JavaScript too. async await functions haven't been ratified in the standard yet, but are planned to be in ES2017. See my answer below for more detail.Dominican
@Ingather async is a syntax / construct. It is not necessarily an intention . This question explicitly distinguishes the two.Quid
@javadba I'm not sure what it is you're trying to say, which is why I'm fairly confident that the question does not in fact explicitly make the distinction you're alluding toIngather
@Ingather On the jvm one can kick off a separate thread that runs tasks asynchronously to the main thread. Then on the main thread one has a choice: wait for those "async" tasks to complete .. or just continue on your business. That is the distinction between the syntax and the intention. Javascript just has no way to convert the async syntax into a non-asynchronous behavior. I was able to understand this question quite well in that regard.Quid
Two answers below show how today it's possible in browser with Service Workers and in Node.js with node-fibers. But both are not recommended and should be AVOIDED.Expedite
F
175

"don't tell me about how I should just do it "the right way" or whatever"

OK. but you should really do it the right way... or whatever

" I need a concrete example of how to make it block ... WITHOUT freezing the UI. If such a thing is possible in JS."

No, it is impossible to block the running JavaScript without blocking the UI.

Given the lack of information, it's tough to offer a solution, but one option may be to have the calling function do some polling to check a global variable, then have the callback set data to the global.

function doSomething() {

      // callback sets the received data to a global var
  function callBack(d) {
      window.data = d;
  }
      // start the async
  myAsynchronousCall(param1, callBack);

}

  // start the function
doSomething();

  // make sure the global is clear
window.data = null

  // start polling at an interval until the data is found at the global
var intvl = setInterval(function() {
    if (window.data) { 
        clearInterval(intvl);
        console.log(data);
    }
}, 100);

All of this assumes that you can modify doSomething(). I don't know if that's in the cards.

If it can be modified, then I don't know why you wouldn't just pass a callback to doSomething() to be called from the other callback, but I better stop before I get into trouble. ;)


Oh, what the heck. You gave an example that suggests it can be done correctly, so I'm going to show that solution...

function doSomething( func ) {

  function callBack(d) {
    func( d );
  }

  myAsynchronousCall(param1, callBack);

}

doSomething(function(data) {
    console.log(data);
});

Because your example includes a callback that is passed to the async call, the right way would be to pass a function to doSomething() to be invoked from the callback.

Of course if that's the only thing the callback is doing, you'd just pass func directly...

myAsynchronousCall(param1, func);
Fib answered 3/2, 2012 at 0:3 Comment(7)
Yeah, I know how to do it correctly, I need to know how to/if it can be done incorrectly for the specific reason stated. The crux is I don't want to leave doSomething() until myAsynchronousCall completes the call to the callback function. Bleh, it can't be done, as I suspected, I just needed the collected wisdom of the Internets to back me up. Thank you. :-)Renettarenew
@RobertC.Barth: Yeah, your suspicions were correct unfortunately.Stilliform
Is it me or only the "done correctly" version work? The question included a return call, before which there should something that waits for the async call to finish, which this first part of this answer doesn't cover...Recondition
@ravemir: The answer states that it isn't possible to do what he wants. That's the important part to understand. In other words, you can't make an asynchronous call and return a value without blocking the UI. So the first solution is an ugly hack using a global variable and polling to see if that variable has been modified. The second version is the correct way.Stilliform
Can somebody explain me what myAsynchronousCall(param1, callBack) is here? This is another function that is called? or this is simply an invocation for namely callback function?Ban
@Leonardo: It's the mysterious function being called in the question. Basically it represents anything that runs code asynchronously and produces a result that needs to be received. So it could be like an AJAX request. You pass the callback function to the myAsynchronousCall function, which does its async stuff and invokes the callback when complete. Here's a demo.Stilliform
the problem I ALWAYS run into is the fact that doSomething() is usually THE ENTIRE PROGRAM. To paraphrase the OP, expecting theoretical programming to reflect reality is an exercise in futility.Towland
D
86

Async functions, a feature in ES2017, make async code look sync by using promises (a particular form of async code) and the await keyword. Also notice in the code examples below the keyword async in front of the function keyword that signifies an async/await function. The await keyword won't work without being in a function pre-fixed with the async keyword. Since currently there is no exception to this that means no top level awaits will work (top level awaits meaning an await outside of any function). Though there is a proposal for top-level await.

ES2017 was ratified (i.e. finalized) as the standard for JavaScript on June 27th, 2017. Async await may already work in your browser, but if not you can still use the functionality using a javascript transpiler like babel or traceur. Chrome 55 has full support of async functions. So if you have a newer browser you may be able to try out the code below.

See kangax's es2017 compatibility table for browser compatibility.

Here's an example async await function called doAsync which takes three one second pauses and prints the time difference after each pause from the start time:

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

function doSomethingAsync () {
  return timeoutPromise(1000);
}

async function doAsync () {
  var start = Date.now(), time;
  console.log(0);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);
}

doAsync();

When the await keyword is placed before a promise value (in this case the promise value is the value returned by the function doSomethingAsync) the await keyword will pause execution of the function call, but it won't pause any other functions and it will continue executing other code until the promise resolves. After the promise resolves it will unwrap the value of the promise and you can think of the await and promise expression as now being replaced by that unwrapped value.

So, since await just pauses waits for then unwraps a value before executing the rest of the line you can use it in for loops and inside function calls like in the below example which collects time differences awaited in an array and prints out the array.

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

function doSomethingAsync () {
  return timeoutPromise(1000);
}

// this calls each promise returning function one after the other
async function doAsync () {
  var response = [];
  var start = Date.now();
  // each index is a promise returning function
  var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
  for(var i = 0; i < promiseFuncs.length; ++i) {
    var promiseFunc = promiseFuncs[i];
    response.push(await promiseFunc() - start);
    console.log(response);
  }
  // do something with response which is an array of values that were from resolved promises.
  return response
}

doAsync().then(function (response) {
  console.log(response)
})

The async function itself returns a promise so you can use that as a promise with chaining like I do above or within another async await function.

The function above would wait for each response before sending another request if you would like to send the requests concurrently you can use Promise.all.

// no change
function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

// no change
function doSomethingAsync () {
  return timeoutPromise(1000);
}

// this function calls the async promise returning functions all at around the same time
async function doAsync () {
  var start = Date.now();
  // we are now using promise all to await all promises to settle
  var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
  return responses.map(x=>x-start);
}

// no change
doAsync().then(function (response) {
  console.log(response)
})

If the promise possibly rejects you can wrap it in a try catch or skip the try catch and let the error propagate to the async/await functions catch call. You should be careful not to leave promise errors unhandled especially in Node.js. Below are some examples that show off how errors work.

function timeoutReject (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
    }, time)
  })
}

function doErrorAsync () {
  return timeoutReject(1000);
}

var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);

async function unpropogatedError () {
  // promise is not awaited or returned so it does not propogate the error
  doErrorAsync();
  return "finished unpropogatedError successfully";
}

unpropogatedError().then(log).catch(logErr)

async function handledError () {
  var start = Date.now();
  try {
    console.log((await doErrorAsync()) - start);
    console.log("past error");
  } catch (e) {
    console.log("in catch we handled the error");
  }
  
  return "finished handledError successfully";
}

handledError().then(log).catch(logErr)

// example of how error propogates to chained catch method
async function propogatedError () {
  var start = Date.now();
  var time = await doErrorAsync() - start;
  console.log(time - start);
  return "finished propogatedError successfully";
}

// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)

If you go here you can see the finished proposals for upcoming ECMAScript versions.

An alternative to this that can be used with just ES2015 (ES6) is to use a special function which wraps a generator function. Generator functions have a yield keyword which may be used to replicate the await keyword with a surrounding function. The yield keyword and generator function are a lot more general purpose and can do many more things then just what the async await function does. If you want a generator function wrapper that can be used to replicate async await I would check out co.js. By the way co's function much like async await functions return a promise. Honestly though at this point browser compatibility is about the same for both generator functions and async functions so if you just want the async await functionality you should use Async functions without co.js. (I recommend just using async/await it's pretty widely supported in most environments that the above strikethrough is supported in.)

Browser support is actually pretty good now for Async functions (as of 2017) in all major current browsers (Chrome, Safari, and Edge) except IE.

Dominican answered 7/11, 2015 at 6:6 Comment(7)
This is a great answer, but for the original posters problem, I think all it does is move the problem up one level. Say he turns doSomething into an async function with an await inside. That function now returns a promise and is asynchronous, so he'll have to deal with the same problem all over again in whatever calls that function.Holmgren
@dpwrussell this is true, there is a creep of async functions and promises in the code base. The best way to resolve promises from creeping in to everything is just to write synchronous callbacks there is no way to return an async value synchronously unless you do something extremely weird and controversial like this twitter.com/sebmarkbage/status/941214259505119232 which I do not recommend. I will add an edit to the end of the question to more fully answer the question as it was asked and not just answer the title.Dominican
It's a great answer +1 and all, but written as is, I don't see how this is any less complicated than using callbacks.Featherveined
@AltimusPrime It's really a matter of opinion, but error handling is much improved over callbacks and you can always use promises directly without async/await which is basically the same as callbacks just yet again with better error handling. The time that promises are trumped by callbacks is when you need to pass a callback to a function to execute multiple times over the lifetime of the function. Also callbacks don't even have to be asynchronous. Promises are best for a single value over time. If you really want to see the whole landscape of values you should read GTOR by kriskowal.Dominican
@AltimusPrime if you need multiple values over time you could use Streams and Async Iterables, you can use these with async/await functions with the for await statement, for example for await (const item of asyncIterable) { } when item and asyncIterable are variables and the rest are keywords. Relevant Links: Kris Kowal's GTOR and asyncIterable proposal repoDominican
What is the final takeaway here ? iiuc : (1) there must be an async loop /handler. (2) but we can do that just once - instead of having a series of increasingly nested handlers (which quickly become unmanageable to read let alone debug) (3) Can we have a single overall try/catch exception handler that will capture errors in any of the async operations? So for those of us who have a nice clean sequential code but need to invoke an async op : then we have to enclose the nice sequential code in one promise loop and then can add an arbitrary number of async operations inside. Correct?Quid
@Quid I would like to answer your questions do you think you could join this room to clarify some of you questions: chat.stackoverflow.com/rooms/237222/…Dominican
A
44

Take a look at JQuery Promises:

http://api.jquery.com/promise/

http://api.jquery.com/jQuery.when/

http://api.jquery.com/deferred.promise/

Refactor the code:


    var dfd = new jQuery.Deferred();


    function callBack(data) {
       dfd.notify(data);
    }

    // do the async call.
    myAsynchronousCall(param1, callBack);

    function doSomething(data) {
     // do stuff with data...
    }

    $.when(dfd).then(doSomething);


Aristotelianism answered 3/2, 2012 at 0:55 Comment(4)
+1 for this answer, this is correct. however, i would update the line with dfd.notify(data) to dfd.resolve(data)Kaylor
Is this a case of the code giving an illusion of being synchronous, without actually NOT being asynchronous ?Durbar
promises are IMO just well organised callbacks :) if you need an asynchronous call in let's say some object initialisation, than promises makes a little difference.Freaky
Promises are not sync.Wardell
A
13

You can force asynchronous JavaScript in NodeJS to be synchronous with sync-rpc.

It will definitely freeze your UI though, so I'm still a naysayer when it comes to whether what it's possible to take the shortcut you need to take. It's not possible to suspend the One And Only Thread in JavaScript, even if NodeJS lets you block it sometimes. No callbacks, events, anything asynchronous at all will be able to process until your promise resolves. So unless you the reader have an unavoidable situation like the OP (or, in my case, are writing a glorified shell script with no callbacks, events, etc.), DO NOT DO THIS!

But here's how you can do this:

./calling-file.js

var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');

var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"

./my-asynchronous-call.js

function init(initData) {
  return function(param1) {
    // Return a promise here and the resulting rpc client will be synchronous
    return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
  };
}
module.exports = init;

LIMITATIONS:

These are both a consequence of how sync-rpc is implemented, which is by abusing require('child_process').spawnSync:

  1. This will not work in the browser.
  2. The arguments to your function must be serializable. Your arguments will pass in and out of JSON.stringify, so functions and non-enumerable properties like prototype chains will be lost.
Avar answered 3/4, 2019 at 21:30 Comment(2)
This answer directly addresses the heart of the question. I may be able to apply this to a particular case of mine.Quid
Having to use async code of a lib (Quasar) to use to populate sunchronous Webpack config - so I obviously can't rewrite none of them - you saved me! Thank you very much!Reichard
S
6

There is one nice workaround at http://taskjs.org/

It uses generators which are new to javascript. So it's currently not implemented by most browsers. I tested it in firefox, and for me it is nice way to wrap asynchronous function.

Here is example code from project GitHub

var { Deferred } = task;

spawn(function() {
    out.innerHTML = "reading...\n";
    try {
        var d = yield read("read.html");
        alert(d.responseText.length);
    } catch (e) {
        e.stack.split(/\n/).forEach(function(line) { console.log(line) });
        console.log("");
        out.innerHTML = "error: " + e;
    }

});

function read(url, method) {
    method = method || "GET";
    var xhr = new XMLHttpRequest();
    var deferred = new Deferred();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status >= 400) {
                var e = new Error(xhr.statusText);
                e.status = xhr.status;
                deferred.reject(e);
            } else {
                deferred.resolve({
                    responseText: xhr.responseText
                });
            }
        }
    };
    xhr.open(method, url, true);
    xhr.send();
    return deferred.promise;
}
Shouldst answered 10/6, 2013 at 20:27 Comment(0)
A
6

What you want is actually possible now. If you can run the asynchronous code in a service worker, and the synchronous code in a web worker, then you can have the web worker send a synchronous XHR to the service worker, and while the service worker does the async things, the web worker's thread will wait. This is not a great approach, but it could work.

Anamorphosis answered 13/4, 2020 at 14:44 Comment(2)
This is a clean approach, still not recommended of coruse :)Lindbom
Backend / node.js solution is still wanting it seems..Quid
S
6
let result;
async_function().then(r => result = r);
while (result === undefined) // Wait result from async_function
    require('deasync').sleep(100);
Shaikh answered 13/10, 2021 at 14:14 Comment(2)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Buna
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. You can find more information on how to write good answers in the help center: stackoverflow.com/help/how-to-answer . Good luck 🙂Organzine
E
2

In Node.js it's possible to write synchronous code which actually invokes asynchronous operations. node-fibers allows this. It's a 3rd party native extension provided as an npm module. It implements fibers/coroutines, so when a specific fiber is blocked waiting for asynchronous operation, the whole program events loop doesn't block - another fiber (if exists) continues its job.

With fibers your code would look like this:

var Fiber = require('fibers');

function doSomething() {
  var fiber = Fiber.current;

  function callBack(data) {
    fiber.run(data);
  }

  myAsynchronousCall(param1, callBack);

  // execution blocks here
  var data = Fiber.yield();
  return data;
}

// The whole program must be wrapped with Fiber
Fiber(function main() {

  var data = doSomething();
  console.log(data);

}).run();

Note, that you should avoid it and use async/await instead. See below a note from the project readme https://github.com/laverdet/node-fibers:

NOTE OF OBSOLESCENCE -- The author of this project recommends you avoid its use if possible. The original version of this module targeted nodejs v0.1.x in early 2011 when JavaScript on the server looked a lot different. Since then async/await, Promises, and Generators were standardized and the ecosystem as a whole has moved in that direction.

I'll continue to support newer versions of nodejs as long as possible but v8 and nodejs are extraordinarily complex and dynamic platforms. It is inevitable that one day this library will abruptly stop working and no one will be able to do anything about it.

I'd like to say thank you to all the users of fibers, your support over the years has meant a lot to me.

Expedite answered 7/3, 2021 at 6:41 Comment(2)
The author of 'node-fibers' recommends you avoid its use if possibleAstronautics
@MuhammadInaamMunir yes, it's mentioned in the answerExpedite
C
1

One thing people might not consider: If you control the async function (which other pieces of code depend on), AND the codepath it would take is not necessarily asynchronous, you can make it synchronous (without breaking those other pieces of code) by creating an optional parameter.

Currently:

async function myFunc(args_etcetc) {
    // you wrote this
    return 'stuff';
}

(async function main() {
    var result = await myFunc('argsetcetc');
    console.log('async result:' result);
})()

Consider:

function myFunc(args_etcetc, opts={}) {
    /*
        param opts :: {sync:Boolean} -- whether to return a Promise or not
    */
    var {sync=false} = opts;
    if (sync===true)
        return 'stuff';
    else
        return new Promise((RETURN,REJECT)=> {
            RETURN('stuff');
        });
}


// async code still works just like before:
(async function main() {
    var result = await myFunc('argsetcetc');
    console.log('async result:', result);
})();
// prints: 'stuff'

// new sync code works, if you specify sync mode:
(function main() {
    var result = myFunc('argsetcetc', {sync:true});
    console.log('sync result:', result);
})();
// prints: 'stuff'

Of course this doesn't work if the async function relies on inherently async operations (network requests, etc.), in which case the endeavor is futile (without effectively waiting idle-spinning for no reason).

Also this is fairly ugly to return either a value or a Promise depending on the options passed in.

("Why would I have written an async function if it didn't use async constructs?" one might ask? Perhaps some modalities/parameters of the function require asynchronicity and others don't, and due to code duplication you wanted a monolithic block rather than separate modular chunks of code in different functions... For example perhaps the argument is either localDatabase (which doesn't require await) or remoteDatabase (which does). Then you could runtime error if you try to do {sync:true} on the remote database. Perhaps this scenario is indicative of another problem, but there you go.)

Courtship answered 28/2, 2021 at 2:27 Comment(0)
V
1

Using Node 16's worker threads actually makes this possible, The following example the main thread is running the asynchronous code while the worker thread is waiting for it synchronously.

Not that is is very useful, but it at least does vaguely what the original question asked by waiting for asynchronous code synchronously.

const {
    Worker, isMainThread, parentPort, receiveMessageOnPort
} = require('worker_threads');
if (isMainThread) {
    const worker = new Worker(__filename);
    worker.on('message', async () => {
        worker.postMessage(await doAsyncStuff());
    });
} else {
    console.log(doStuffSync());
}

function doStuffSync(){
    parentPort.postMessage({fn: 'doStuff'});
    let message;
    while (!message) {
        message = receiveMessageOnPort(parentPort)
    }
    return message;
}

function doAsyncStuff(){
    return new Promise((resolve) => setTimeout(() => resolve("A test"), 1000));
}
Vauntcourier answered 7/6, 2021 at 4:18 Comment(0)
B
0

This ability of promises includes two key features of synchronous operations as follows (or then() accepts two callbacks). When you get the result, call resolve() and pass the final result. In case of error, call reject().

The idea is that the result is passed through the chain of .then() handlers.

const synchronize = (() => {
    let chain = Promise.resolve()
    return async (promise) => {
        return chain = chain.then(promise)
    }
})()
Barry answered 23/6, 2021 at 7:7 Comment(0)
S
0

I wondered the same thing and noticed that the currently best answer contains the right idea in my mind for most use cases, but forgets to mention a couple of things. When using a global variable to lock execution, we're talking about Semaphores, and there are some packages which implement those (my recommendation: async-sema). I think this makes it a little simpler and cleaner.

import { Sema } from 'async-sema'

const sema = new Sema(1) // allow only one concurrent process

async function doSomething() {

  var data;
   
  await sema.acquire();
  // only one process gets inside here
  data = await myAsynchronousCall(param1);
  sema.release();

  return data;
}

The advantage is obviously that the rest of your program can still do other things asynchronously, only the single block is kind of forced to be synchronously. Disadvantage is that you have to be careful what and where to lock, try/catch/finally possible errors, etc.

Sheldonshelduck answered 21/2, 2023 at 12:1 Comment(0)
S
-2

In Node.js is possible to do it using the deasync

  • npm install --save deasync

Code example:

function asyncToSync(promise) {
  let done = false;
  let result;

  promise.then((r) => {
    result = r;
    done = true;
  }).catch((e) => {
    console.error(e);
    done = true;
  });

  require('deasync').loopWhile(() => !done);

  return result;
}

And using the function:

const value = asyncToSync(Promise.resolve(3));
console.log(value) // 3
Sporocyte answered 13/7, 2023 at 21:35 Comment(0)
I
-3

You can also convert it into callbacks.

function thirdPartyFoo(callback) {    
  callback("Hello World");    
}

function foo() {    
  var fooVariable;

  thirdPartyFoo(function(data) {
    fooVariable = data;
  });

  return fooVariable;
}

var temp = foo();  
console.log(temp);
Indoiranian answered 28/11, 2019 at 5:32 Comment(1)
Well, if the thirdPartyFoo is doing some async stuff, then you will get null in temp alwaysPhosphate
P
-7

The idea that you hope to achieve can be made possible if you tweak the requirement a little bit

The below code is possible if your runtime supports the ES6 specification.

More about async functions

async function myAsynchronousCall(param1) {
    // logic for myAsynchronous call
    return d;
}

function doSomething() {

  var data = await myAsynchronousCall(param1); //'blocks' here until the async call is finished
  return data;
}
Pricking answered 29/8, 2018 at 11:39 Comment(1)
Firefox gives the error: SyntaxError: await is only valid in async functions and async generators. Not to mention that param1 is not defined (and not even used).Shoer

© 2022 - 2024 — McMap. All rights reserved.