Javascript - 推迟承诺解决方案

时间:2018-06-05 16:17:48

标签: javascript promise

我有一项服务可以产生一些确认警报并等待用户交互,由Promise管理。

如果在用户应答第一个确认警报之前产生了新的确认警报,则该服务会将其存储在某种等待列表中。并且一旦前一个用户将被解雇,它将立即显示

let waitList = []
let activeAlert = null;

function createAlert(){
   if(!activeAlert){
       let pr = new Promise((resolve, reject) => {
           // do stuff to show the alert
           if('user click ok') resolve();
           else reject();
       });
       activeAlert = pr;
       return pr;
   }
   else {
       let p = new Promise();
       waitList.push(p);
       return p;
   }
}

let alert = createAlert();
alert.then(()=>{
    // the user clicked OK
}).catch(()=>{
    // the user click CANCEL
});

let alert2 = createAlert();
alert2.then(()=>{
    // the user clicked OK on the second one
}).catch(()=>{
    // the user click CANCEL on the second one
});

我知道Promise反模式的概念,并且Defer对象已被弃用并被认为已过时。我无法理解如何定义" resolve"并且"拒绝"保存在数组中的Promise的条件。

2 个答案:

答案 0 :(得分:1)

如果不首先保存一些引用,则无法从其范围之外解析Promise。如果要从数组外部解决它们,还应该将相关的解析和拒绝回调推送到对象中,以便可以在该范围外使用它们。 EX:

let myRefHolder = {};
let toResolve = new Promise((res, rej) => {
    myRefHolder.resolutionCallback = res;
    //other code
});

然后在偶数处理程序中:

clickHandler = () => {
    myRefHolder.resolutionCallback(resolutionValue);
    //other code
}

然后你只需要改变这个结构以适应所有的承诺和回调...而不是myRefHolder对象,你可以有一个形状像myRefHolders的对象数组,一次用于每个承诺!

另一种方法是直接在Promise中分配按钮事件处理程序:

new Promise((rej, res) => yourButtonElement.addEventListener(‘click’, res));

单击按钮即可解决此问题。您也可以传递更复杂的内联函数,而不是引用更复杂的逻辑。 由于一个事件可以有多个处理程序,你可以继续为每个承诺添加该事件 - 但它可能会变得混乱,因为你必须在实际解析Promise之前删除监听器(我使用它的示例1行代码可能会去泄漏内存,因为该处理程序保持活动状态,并使垃圾收集器无法释放Promise内存)

如果您要问的是我如何/在一系列承诺中捕获特定承诺,那就像myArray[index].then(() => {})一样简单 如果您正在等待一系列承诺,就像Promise.all(myArray)

一样简单

答案 1 :(得分:1)

您可以保留先前警报的承诺链(与警报的承诺分开,以便您可以根据需要解决/拒绝这些警报),然后在警报完成时让每个承诺解决:

// Kick things off with a resolved promise
let lastPromise = Promise.resolve();

function createAlert(msg) {
  // Create the promise for this alert, but don't start it yet
  let resolve, reject;
  const p = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });
  // Wait until the last alert is complete before starting this one
  lastPromise = lastPromise.then(() => {
    // Start this alert, and when it's done, resolve our chain promise
    // ...
    // later, if user confirms or whatever:
      resolve();
    // or if they cancel or whatever:
      reject();
    // Slave our chain to the resolution/rejection of the alert
    return p.catch(e => undefined).then(v => undefined);
  });
  // Return the alert promise
  return p;
}

使用非常粗略"对话框运行示例"使用确定和取消按钮分别解决和拒绝承诺:



// Kick things off with a resolved promise
let lastPromise = Promise.resolve();

function createAlert(msg) {
  console.log("createAlert('" + msg + "')");
  // Create the promise for this alert, but don't start it yet
  let resolve, reject;
  const p = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });
  // Wait until the last alert is complete before starting this one
  lastPromise = lastPromise.then(() => {
    // Start this alert, and when it's done, resolve our chain promise
    // This is obviousyl VERY CRUDE, just for demo purposes
    console.log("showing '" + msg + "'");
    function handler(e) {
      switch (e.target.value) {
        case "OK":
          console.log("user clicked OK on '" + msg + "'");
          close();
          resolve();
          break;
        case "Cancel":
          console.log("user clicked Cancel on '" + msg + "'");
          close();
          reject();
          break;
      }
    }
    function close() {
      alert.style.display = "none";
      alert.querySelector(".message").innerHTML = "";
      alert.removeEventListener("click", handler);
    }
    const alert = document.getElementById("alert");
    alert.querySelector(".message").appendChild(
      document.createTextNode(msg)
    );
    alert.addEventListener("click", handler);
    alert.style.display = "";

    // Slave our chain to the resolution/rejection of the alert
    return p.catch(e => undefined).then(v => undefined);
  });
  // Return the alert promise
  return p;
}

function test(msg) {
  createAlert(msg)
    .then(() => {
      console.log("alert resolved for '" + msg + "'");
    })
    .catch(() => {
      console.log("alert rejected for '" + msg + "'");
    });
}

test("one");
test("two");
test("three");

.as-console-wrapper {
  max-height: 100% !important;
}

<div id="alert" style="display: none">
  <div class="message"></div>
  <input type="button" value="OK">
  <input type="button" value="Cancel">
</div>
&#13;
&#13;
&#13;