Javascript - Отложить обещание резолюции - PullRequest
0 голосов
/ 05 июня 2018

У меня есть служба, которая выдает некоторое подтверждение-предупреждение и ожидает взаимодействия с пользователем, управляемым 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 устарел и считается устаревшим.Я не могу понять, как определить условия «разрешить» и «отклонить» для Обещания, сохраненного в массиве.

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Вы можете сохранить цепочку обещаний для предыдущих оповещений (отдельно от собственного обещания оповещения, чтобы вы могли разрешить / отклонить их в зависимости от ситуации), а затем разрешить каждое обещание, когда оповещение будет завершено:

// 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>
0 голосов
/ 05 июня 2018

Обещания не могут быть разрешены вне их пределов без предварительного сохранения некоторых ссылок.Если вы хотите решить их извне массива, вы должны также вставить соответствующие разрешения и отклонить обратные вызовы в объект, чтобы их можно было использовать вне этой области.Пример:

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

И затем в четном обработчике:

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

Тогда вам просто нужно немного изменить эту структуру, чтобы учесть все ваши обещания и обратные вызовы ... ВместоmyRefHolder объект, вы можете иметь массив объектов в форме myRefHolders, один раз для каждого Обещания!

Альтернативой является назначение обработчика события кнопки непосредственно в Обещании:

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

Это будет решено, когда вы нажмете на кнопку.Вместо ref вы также можете передать более сложную встроенную функцию, которая имеет более сложную логику.Поскольку у события может быть несколько обработчиков, вы можете продолжать добавлять к этому событию каждое ваше обещание - но оно может стать грязным, потому что вам придется удалить прослушиватель перед фактическим разрешением обещания (пример кода строки 1, который я использовал, скорее всего, будетутечка памяти из-за того, что этот обработчик остается живым и не позволяет сборщику мусора освободить память Promise)

Если вы спрашиваете, как мне затем / поймать конкретное обещание в массиве обещаний, это какпросто, как myArray[index].then(() => {}) Если вы ожидаете массив обещаний, просто, как Promise.all(myArray)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...