Brane
Brane

Reputation: 171

JavaScript: how can I use async/await to "await" something that happens in MutationObserver?

I have a forEach loop that processes data in an array. Somewhere in the middle of that loop I have to wait for a change in a DOM element, grab that change, process it, and only then can I continue processing the array.

I'm hoping to see this in console:

Preparing "aaa"
Waiting for result on "aaa"
Processing result on "aaa": <random number>
Got result for "aaa": <random number>something`

And the same thing for each element in stuffToProcess array in the code snippet below. It's a simplified example of the code.

I realize similar questions have been asked and answered countless times before, but after reading through many of them, and trying many different things for hours, I still can't figure this one out.

function dummy() {
  $('#trackMe').text(Math.random());
}

async function doWork(stuffToProcess) {
  let target = $('#trackMe')[0];
  let config = { attributes: true, childList: true, characterData: true, values: true };
  
  let observer = new MutationObserver(function(mutations,item) {
    console.log('Processing result on "%s": %s', item, target.innerText);
    item = item + 'something';
    return new Promise(resolve => {
      resolve(item);
    });
  });

  observer.observe(target, config);

  stuffToProcess.forEach(async function(item) {
    console.log('Preparing "%s"', item);
    console.log('Waiting for result on "%s"', item);
    let change = await observer(item);
    //^^^ this needs to "await" for data from observer before the loop continues
    console.log('Got result for "%s": %s', item, change);
  });

  //observer.disconnect();

}

doWork(['aaa', 'bbb', 'ccc']);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="trackMe">No changes yet</p>
<button onclick="dummy()">Click me to change</button>

Upvotes: 4

Views: 4068

Answers (2)

fercho23
fercho23

Reputation: 1

Here is an example using only JavaScript, I hope it helps you.

function getData() {
    return new Promise(function(resolve, reject) {
        // resolve();
        // reject();
    });
}

function example1() {
    // code ...

    async function getAsyncData() {
        let data = await getData();
        console.log(data);
        // code ...
    }

    let element = document.getElementById(...);
    let observer = new MutationObserver(function(mutations) {
        getAsyncData();
    });
    let config = {attributes: true, childList: true, characterData: true};
    observer.observe(element, config);

    // code ...
}

Upvotes: -1

Brane
Brane

Reputation: 171

Well, I managed to solve it somehow. Probably not the cleanest solution though, so if anyone recommends any improvements on this, I'll happily edit the solution / upvote your answer.

function dummy() {
  $('#trackMe').text(Math.random());
}

async function doWork(stuffToProcess) {
  let target = $('#trackMe')[0];
  let config = {
    attributes: true,
    childList: true,
    characterData: true,
    values: true
  };

  let observer;

  function isItDone(item) {
    return new Promise(resolve => {

      observer = new MutationObserver(function(mutations) {
        console.log('Processing result on "%s": %s', item, target.innerText);
        result = target.innerText + 'something';
        resolve(result);
      });

      observer.observe(target, config);
    });
  }


  for (index in stuffToProcess) {
    console.log('Preparing "%s"', stuffToProcess[index]);
    console.log('Waiting for result on "%s"', stuffToProcess[index]);

    let change = await isItDone(stuffToProcess[index]);
    observer.disconnect();

    console.log('Got result for "%s": %s', stuffToProcess[index], change);
  }
}

doWork(['aaa', 'bbb', 'ccc']);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="trackMe">No changes yet</p>
<button onclick="dummy()">Click me to change</button>

Upvotes: 3

Related Questions