簡體   English   中英

Javascript-延遲承諾解析

[英]Javascript - Defer Promise resolution

我有一項服務,該服務會產生一些確認警報並等待用戶交互,並由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對象已棄用並被認為已過時。 我不明白如何為數組中保存的Promise定義“解析”和“拒絕”條件。

如果不先保存一些引用,就無法從其范圍之外解決承諾。 如果要從數組外部解決它們,則還應將相關的resolve和拒絕回調推入對象,以便可以在該范圍之外使用它們。 例如:

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

然后在偶數處理程序中:

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

然后,您只需要稍微更改此結構即可容納所有的myRefHolder和回調...除了myRefHolder對象之外,您還可以擁有形狀類似於myRefHolders的對象數組,每個Promise一次!

一種替代方法是直接在Promise中分配按鈕事件處理程序:

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

當您單擊按鈕時,將解決此問題。 除了ref之外,您還可以傳遞具有更復雜邏輯的更復雜的內聯函數。 由於一個事件可以有多個處理程序,因此您可以為每個promise繼續添加該事件-但是它可能會變得混亂,因為在真正解決Promise之前,您必須先刪除偵聽器(我使用的示例1行代碼很可能會泄漏內存,因為該處理程序保持活動狀態,並阻止垃圾收集器釋放Promise內存)

如果您要問的是我然后如何/在一個Promise數組中捕獲一個特定的Promise,就像myArray[index].then(() => {})如果您正在等待一個Promise數組,就像Promise.all(myArray)一樣容易

您可以為先前的警報保留一個諾言鏈(與警報自己的諾言分開,因此您可以酌情解決/拒絕這些諾言),然后在警報完成時解決每個諾言:

// 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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM