JSFiddle - React, Tailwind, and code Playground

by lid0

HTML

<div id="app">
  <div style="border:1px solid gray;padding:5px;border-radius:3px;margin-bottom:5px;">
    1. click <kbd>"run/add tasks"</kbd> button once or many times, to start and add more tasks <br>
    2. click <kbd>cancel</kbd> button, to abort all in progress tasks.<br>
    3. <kbd>reset app()</kbd> to clear output and reset application state.

  </div>

  <div style="margin-top:15px;margin-bottom:15px;">
    Status: <div id="status">
      -
    </div>
  </div>

  <div>
    <button onClick="abort()">
      cancel
    </button>

    <button onClick="run()">
      RUN/ADD tasks
    </button>
    <progress id="progress" max=0 value=0></progress>
    <output id="progressStats">0 / 0</output>
  </div>


  <hr>

  <button onClick="resetApp()">
    reset app ()
  </button> clear output,and reset progress bar


  <hr>



  <div>
    <div style="margin-top:5px;">
      Output:
    </div>
    <pre id="result">
</pre>
  </div>

</div>

CSS

#status {
  border: 1px solid #cfcfcf;
  border-radius: 3px;
  padding: 3px;
  display: inline-block;
  min-width: 150px;
}

#app.aborted #status {
  background: #ea5e5e;
}

#app.running #status {
  background: #52c8ce;
}

#app.completed #status {
  background: #80e606;
}


b.aborted {
  color: red;
}

span.aborted {
  color: red;
}

b.success {
  color: darkgreen;
}

b span.success {
  color: darkgreen;
}

#result {
  border: 1px solid #000;
  padding: 3px;
  border-radius: 3px;
}


#app.aborted ::-moz-progress-bar {
  background: #ea5e5e;
}

#app.running ::-moz-progress-bar {
  background: #52c8ce;
}

#app.completed ::-moz-progress-bar {
  background: #80e606;
}

JavaScript

// Author: lidlanca 2021 March 25


var cancelController = new AbortController(); // abort controller. can only be used once to signal abort
var requestPromises = []; // all ongoing request promises 

// UI elements
var resultEl = document.getElementById("result")
var statusEl = document.getElementById("status")
var progressEl = document.getElementById("progress")
var progressStatsEl = document.getElementById("progressStats")
var appEl = document.getElementById("app")

// App State
var running = false
var aborted = false

var requestCounter = {
  requestAbortedCount: 0,
  requestFulfilled: 0,
  requestScheduled: 0,
}




// mock fetch(), simulate random request time.
async function fetch(url, options) {
  ({
    signal
  } = options)
  return new Promise(function(resolve, reject) {

    signal.addEventListener('abort', () => {
      // in a real fetch it would throw AbortError
      reject(url + " aborted")
    })
    setTimeout(() => (resolve(url + " Completed Successfully")), 1000 * (Math.random() * 10 + 3))
  })

}




// set the app container with a status class for styling. 
function setAppActiveStatus(cls) {
  var classes = ["running", "aborted", "completed"]
  appEl.classList.remove(...classes)
  appEl.classList.add(cls)
}


// abort any pending tasks, not yet completed in the current run.
function abort() {
  if (!running) {
    console.log("skipped abort called, no running tasks")
    return
  }

  // trigger the abort signal.
  cancelController.abort()
  cancelController = new AbortController(); // create new instance controller, for the next run. not reusuable 


  // update app state flags.
  aborted = true
  running = false;

  setAppActiveStatus("aborted")
}


// print message to the output box
function print(msg) {
  if (msg.includes("aborted")) {
    msg = "<b class='aborted'>" + msg + "</b>"
  } else if (msg.includes("Completed Successfully")) {
    msg = "<b class='success'>" + msg + "</b>"

  }
  resultEl.innerHTML += msg + "\n"
}

function...