我有一项服务可以产生一些确认警报并等待用户交互,由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的条件。
答案 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;