How to track individual JavaScript Processes?

Viewed 92

The title is likely misleading for I'm not sure how to summarize my question in one sentence.

I have a scenario where my script has to post data to multiple URLs in parallel and I'm struggling to figure out how to visually track what's happening with each individual URL (i.e. what's being posted and what's being returned). Here is my code:

const axios = require('axios');

const postData = async (order_id) => {
    for(let i = 0; i < 10; i++){
        let data = await grabDataFromSomewhere(...);
        await axios.post(`http://example.net/orders/${order_id}`, {data})
            .then(response => {
                //console.log(response.data);
                console.log(i, `POSTING TO http://example.net/orders/${order_id}`);
                console.log("--- Response:", response.data)
            })
    }
}

const orders = ['5f96499a3a19135ad163', '99a3a19135ad1630238', '6499a3a19135ad16302']

orders.forEach(id => {
    postData(id)
})

The script works well in terms of posting the right data to the right URL, but the console output, obviously, is one big mess as all the axios requests finish and and dump its output to the same console.

What's the best way to keep an eye on the output of each individual call to the postData function in its own dedicated console?

For those who use screen on Linux, a good way to visualize what I'm looking for is imagining each call to postData spawning a new screen which I can attach any time and see the function's output.

1 Answers

I would suggest the following code. The idea is to make all the requests in parallel, but to log them in the order that they are sent out. If you run the following code and check the console, you will see that the responses occur at random intervals, but that they are always logged in the correct order in the browser. The trick is to create a map of promises representing the post requests, then chain them in such a way that when the first request returns, it is logged, then when the second one returns it is logged, and so on. If a request returns out of order, its promise will still be resolved, but we will only log it once all of its predecessors have arrived.

I realise this is not exactly what you were asking for, but this is how I would go around trying to solve the problem that you are facing.

Also, you have a multi-dimensional array, so I would flatten that out into a single-dimensional one before mapping its contents to Ajax requests.

This solution is based on an article by Jake Archibald https://web.dev/promises/

const orders = ['alpha', 'beta', 'gamma', 'delta', 'epsilon']

function postToAxios(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('in set timeout', data);

      if (data === 'beta') {
        reject('rejected: ' + data);
      } else {
        resolve('resolved: ' + data);
      }
    }, Math.random() * 1000);
  });
}

function createLogEntry(data) {
  const el = document.createElement('div');
  el.className = "log-entry";
  el.textContent = data;
  return el;
}

function createErrorEntry(data) {
  const el = document.createElement('div');
  el.className = "error-entry";
  el.textContent = data;
  return el;
}

orders.map(postToAxios)
  .reduce(function(sequence, promise) {
    return sequence
      .then(function() {
        return promise;
      }).then(function(result) {
        log.append(createLogEntry(result))
      }, function(reason) {
        log.append(createErrorEntry(reason));
      });
  }, Promise.resolve()).then(() => {
    console.log('all done');
  });
.log-entry,
.error-entry {
  margin: 5px;
  border: dotted 1px grey;
  padding: 10px;
}

.error-entry {
  color: red;
  border-color: currentcolor;
}
<div id="log"></div>

Related