user5507535
user5507535

Reputation: 1800

JS - Return empty promise and resolve it later

In JS, I would like to:

  1. Define a function that defines a promise.
  2. This function then has an event to resolve the promise.
  3. The function returns the promise without being resolved yet.
  4. When the promise is resolve the caller will receive the value of the resolve.

Something like this:

function my_func() {
    // This creates an empty promise.
    const p = Promise;

    // When a user clicks a button in UI then we resolve the promise.
    // This would be in an event!
    // p.resolve('user clicked OK');

    // Returns empty promise.
    return p;
}

function main() {
    // Here when the promise is resolved then we get the value.
    my_func().then(function(v) {
        console.log(v);
    });
}

Upvotes: 1

Views: 2716

Answers (2)

user5507535
user5507535

Reputation: 1800

Found answers here: Creating a (ES6) promise without starting to resolve it

deferreds can be passed around as I want and then the promise can be resolved or rejected somewhere else.
Haven't tested this in code yet, so don't know if there's any problem with this approach.

function my_func() {
  const deferreds = [];
  const p = new Promise(function (resolve, reject) {
    deferreds.push({ resolve: resolve, reject: reject });
  });
  const btn = document.querySelector('.btn');

  btn.addEventListener('click', event => {
    deferreds[0].resolve('User clicked button!');
  }, {once: true});

  return p;
}

function main() {
  my_func().then(function (v) {
    console.log(v);
  });
}

main();
<button class="btn">
    Hi! Click me
</button>

Upvotes: 3

Mulan
Mulan

Reputation: 135197

It seems like an odd design, but as Bergi comments, there's nothing stopping you from doing it -

function my_func () {
  return new Promise(r =>
    document.forms.myapp.mybutton.onclick = r
  )
}

function main () {
  my_func().then(event => console.log(event.target))
}

main()
<form id="myapp">
  <button type="button" name="mybutton">Click me</button>
</form>

A Promise can be resolved a maximum of one time, so it probably makes sense to automatically remove the event listener after the first click. We could rename my_func to onclick and give it a parameter to make it reusable -

function onclick(elem) {
  return new Promise(r =>
    elem.addEventListener("click", r, {once: true})
  )
}

function main () {
  onclick(document.forms.myapp.mybutton)
    .then(event => console.log(event.target))
    
  onclick(document.forms.myapp.otherbutton)
    .then(event => console.log(event.target))
}

main()
<form id="myapp">
  <button type="button" name="mybutton">A</button>
  <button type="button" name="otherbutton">B</button>
</form>

Now onclick can be used in more interesting ways. For example, we could make a button that needs two clicks before the effect is triggered -

function onclick(elem) {
  return new Promise(r =>
    elem.addEventListener("click", r, {once: true})
  )
}

function main () {
  onclick(document.forms.myapp.mybutton)
    .then(event => console.log(event.target))
    
  onclick(document.forms.myapp.otherbutton)
    .then(_ =>
      onclick(document.forms.myapp.otherbutton)
        .then(event => console.log(event.target))
    )
}

main()
<form id="myapp">
  <button type="button" name="mybutton">click once</button>
  <button type="button" name="otherbutton">click twice</button>
</form>

Upvotes: 1

Related Questions