JSFiddle - React, Tailwind, and code Playground

HTML

<p>
A <tt>Promise</tt> is like a container that will resolve (or not) to a value. This may have already happened, or it may happen in the future.
</p>

<p>
<tt>Promise</tt> can be in one of three states:
</p>

<dl>
  <dt>Unresolved</dt>
  <dd>The value has not yet been resolved, and will resolve in the future</dd>
  <dt>Resolved</dt>
  <dd>The value has been resolved can be used immediately</dd>
  <dt>Rejected</dt>
  <dd>The value has been rejected? Anyway it means there was an error or whatever</dd>
</dl>

<p><tt>Promise</tt> exposes a <tt>then</tt> method that allows a user to <em>bind</em> a function that will handle the resolved value. The function can be bound either before or after the value has actually been resolved.</p>

<p>
<code>
unresolvedPromise.then((value) => {
  // do something with value when it's resolved in the future
})

alreadyResolvedPromise.then((value) => {
  // do something with value immediately
})

rejectedPromise.then((value) => {
  // this promise got rejected, so this function will never get called
  // if a promise is unresolved then gets rejected, it will also not
  // call functions bound with then
})
</code>
</p>

<p>How does a value actually get provided to a <tt>Promise</tt>? Whoever creates the promise has to call the special <tt>resolve</tt> function (or <tt>reject</tt>). The special functions are provided to a callback that gets passed to the <tt>Promise</tt> constructor</p>

<code>
// the creator of the promise provides a function that handles the special resolve/reject functions
const getSomeNumber = new JonPromise(function(resolve, reject) {
  setTimeout(() =&gt; {
    resolve(Math.ceil(Math.random() * 10));
  }, 1000); // &lt;- happens 1 second in the future
  // theres some weird inversion of control here make sure you understand it
});

getSomeNumber.then((value) =&gt; {
  alert(`wow we got the number ${value}`)
});
</code>
<button>Run code</button>

<p>This definition of <tt>JonPromise</tt> is not fully functional...

CSS

code {
  white-space: pre;
}

button {
  display: block;
}

JavaScript

class JonPromise { // Vanilla JavaScript PogChamp
  constructor(f) {
  	this.boundToThen = [];
    this.boundToCatch = [];
    
  	const resolve = (someValue) => {
      this.boundToThen.forEach(g => g(someValue));
    };
    const reject = (someError) => {
    	this.boundToCatch.forEach(h => h(someError) );
    }
  	f(resolve, reject);
  }
  
  then(f) {
  	this.boundToThen.push(f);
  }
  
  catch(f) {
  	this.boundToCatch.push(f);
  }
}

// magic run code block stuff
document.addEventListener('click', (e) => {
	if (e.target.tagName !== 'BUTTON') {
  	return;
  }
  let p = e.target;
  while (p.tagName !== 'CODE') {
   	p = p.previousSibling;
  }
  const code = p.innerText;
  eval(code);
});