How to prevent parallel execution of asynchronous init method in JavaScript?

Related searches

I want to preload a search index in JavaScript as soon as the page is loaded, so that the user may not have to wait for it to be build. I know JavaScript is single threaded and a lock is normally not required, but I am not sure if the following code is sufficient:

class Index
{
  constructor()
  {
    this.index = null;
  }

  async init()
  {
    this.index = await queryDatabase();
  }

  async search(input)
  {
    if(!this.index) {await this.init();}
    return this.index.query(input);
  }
}

Index index = new index();
index.init(); // preload
myButton.addEventListener("click",console.log(index.search()));

Can it happen that a user clicks on myButton before init() is finished and that init is called twice? If not, how can I prevent that in the best way?

init() is async , it returns a promise, you can add the event listener after querying the database :

class Index {
  constructor() {
    this.index = null;
  }

  async init() {
    this.index = await queryDatabase();
  }

  async search(input) {
    if (!this.index) {
      await this.init();
    }
    return this.index.query(input);
  }
}

Index index = new index();

index.init().then(() => {
  // add the event listener after the init
  myButton.addEventListener("click", function(){
   console.log(index.search()) 
  });
});

How to run async JavaScript functions in sequence or parallel, The async and await keywords are a great addition to Javascript. They make it You run through your array in a loop, wanting them to run in parallel. But instead Let's imagine we need to make a series of asynchronous function calls. They could Then call .reduce() to run each promise run in sequence. If you want to run than in parallel, then we use.map () to kick everything off, then Promise.all () to gather them back up again. If you want to run them sequentially, create a fake Promise to start then chain. Then call.reduce () to run each promise run in sequence. Also, if you need to brush up on Promises, check one of these articles:

Same as @Taki (upvote his) but using async/await syntax 100%.

IIFE syntax : https://jack.ofspades.com/es6-iife-with-fat-arrow-functions/

class Index {
  constructor() {
    this.index = null;
  }

  async init() {
    this.index = await queryDatabase();
  }

  async search(input) {
    // should never happend
    if (this.index === null) {
      await this.init();
    }

    return this.index.query(input);
  }
}

const index = new index();

(async() => {
  await index.init();

  // add the event listener after the init
  myButton.addEventListener('click', console.log(index.search()));
})();

Async patterns in Node.js: only 5+ different ways to do it!, So let's start our journey through the jungle of Node.js async patterns To the method doing something async, you pass a callback (taking of using async. parallel for parallelizing CPU intensive code in Node.js, to add another callback parameter to myKitchenModule.init , turning Keep it simple stupid! Combining Asynchronous and Parallel Execution in a Polyglot HTTP Web Service: As we have discussed in a previous blog post, GraalVM JavaScript relies on a relaxed share-nothing parallel

You can also init it in constructor.

class Index
{
  constructor(){this.index = queryDatabase();}
  async search(input){
    return (await this.index).query(input);
  }
}

or simply change search be normal function and just assume the user would call init() and wait for it.

class Index
{
  constructor(){this.index = null;}
  async init(){this.index = await queryDatabase();}

  search(input)
  {
    //just assume the `init()` is called.
    return this.index.query(input);
  }
}

*you can actually make the constructor return a Promise<Index> and instantiate it like let index = await new Index but it's not widely used and may cause confusion. (An alternative would be factory method)

** also note that your implementation is not safe, one can easily call search multiple times and you (wrongly) calls init multiple times. (which is valid use case like Promise.All(search(A),search(B)))

Keep Your Promises in TypeScript using async/await, Learn about Asynchronous Functions, Parallel and Serial Execution of Promises, As TypeScript is a superset of JavaScript, existing JavaScript programs are also This method prevents chances of any programming errors. In the case of a unit test, I choose not to, but the consuming application might decide to do so, for reasons of either responsiveness or parallel execution. For more information, see Stephen Toub’s blog post, “Should I Expose Asynchronous Wrappers for Synchronous Methods?” (bit.ly/1shQPfn).

The above two answers are "spot on."

I would also like to offer the opinion that I do not recommend the bit of code that now appears in the search() method:

 if(!this.index) {await this.init();}

Instead, "just make sure that it is ready-to-use before you install event-listeners and so forth which will attempt to use it."

Tips for using async functions (ES2017), [2016-10-22] dev, javascript, esnext. (Ad, please don't block) While executing the body of the async function, return x resolves the Promise p with x , while throw err rejects p with err . Executing them in parallel tends to speed things up. An async function is a function declared with the async keyword. Async functions are instances of the AsyncFunction constructor, and the await keyword is permitted within them. The async and await keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains.

I wonder if you really need that class infrastructure for this. If Index is as simple as that, you might be better to just create the search function with access to the Promise returned by queryDatabase. This version does that, and demonstrates with a progress bar that simulates how long until queryDatabase returns. You can click the search button once or more before it returns, and the output will be shown only when the data is available.

queryDatabase is faked with the object {foo: 42, bar: 99, baz: 7}, returning values for "foo", "bar", and "baz".

const search = ((index) => 
  async (input) => (await index) .query (input)
) (queryDatabase ())

myButton .addEventListener ('click', async () => {
  log (await search (getTerm ()))
})
.bar {border: 1px solid #666; height: 15px; width: 100%;} .bar .in {animation: fill 5s linear 1; height: 100%; background-color: blue;} @keyframes fill {0% {width: 0%;} 100% {width: 100%;}} select, button {margin-left: 1em;}
<p><label>Search Term <select id="term"><option>foo</option><option>bar</option><option>baz</option></select></label><button id="myButton">Search</button></p><div class="bar"><div class="in"></div></div><pre id="output">Output:</pre>
<script>
const queryDatabase = () => new Promise ((res) => setTimeout(() => res ({query: key => ({foo: 42, bar: 99, baz: 7})[key]}), 5000))
const myButton = document.getElementById ('myButton')
const term = document.getElementById ('term')
const output = document.getElementById ('output')
const getTerm = () => term.options[term.selectedIndex].value
const log = (msg) => output.innerHTML += '\n' + msg 
</script>

async function, An async function is a function declared with the async keyword. we must be mindful of error handling behavior when dealing with concurrent asynchronous operations. Execution gets here almost instantly const slow = await async function � block � break � class � const � continue � debugger � dowhile� The code calls an asynchronous method, CreateMultipleTasksAsync, which drives the application. Add the following support methods to the project: ProcessURLAsync uses an HttpClient method to download the contents of a website as a byte array. The support method, ProcessURLAsync then displays and returns the length of the array.

In JavaScript, we often need to deal with asynchronous behavior, which can be confusing for programmers who only have experience with synchronous code. This guide will explain what asynchronous code is, some of the difficulties of using asynchronous code, and ways of handling these difficulties.

After the asynchronous call returns, call ThrowIfCancellationRequested on the token. In the following example: await Task.Delay(5000, cts.Token); represents long-running asynchronous background work. BackgroundResourceMethod represents a long-running background method that shouldn't start if the Resource is disposed before the method is called.

Comments
  • You could pass myButton into init() and add the event listener only after the query returns.
  • this.index = await queryDatabase(); myButton.addEventListener(...);
  • myButton.addEventListener("click",console.log(index.search())); Is a problematic. You're binding the return value of console.log as the event listener. Meaning, whatever is currently logged to your console, has nothing to do with whether somebody clicked that button.
  • @Yoshi and the fact index.search is async make it even worse I believe. (unless OP really want to log Promise)
  • @yoshi: Sorry, I made a mistake when simplifying my real code to the example, I just wanted to print the search results. This should be an asynchronous arrow function that waits for the results and then prints them.