通知提示排队显示时如何保证队列顺序不混乱?

闲人东焕 阅读 21

最近在做消息提示功能,需要实现多个通知排队显示的效果。现在的问题是当快速连续触发多个通知时,虽然队列能正确存入,但前一个通知还没完全消失,下一个就提前显示了,导致视觉上重叠。

我尝试用setTimeout控制显示间隔,但发现如果前一个通知的消失动画还没执行完,下一个就会被触发。代码逻辑是这样的:

let queue = [];
function showNotification(msg) {
  queue.push(msg);
  if (queue.length === 1) {
    displayNext();
  }
}

function displayNext() {
  if (queue.length > 0) {
    const msg = queue.shift();
    notificationEl.textContent = msg;
    notificationEl.style.display = 'block';
    setTimeout(() => {
      notificationEl.style.display = 'none';
      displayNext();
    }, 3000); // 3秒后隐藏
  }
}

但实际测试时发现,当快速点击多次按钮时,后面的通知会直接覆盖前面的内容,好像setTimeout没有起到排队作用。有没有更好的方式让通知严格按顺序显示并保持间隔?

我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
Top丶嘉倪
你这段代码的思路是对的,但问题出在:**你只在队列长度为1的时候调用 displayNext,但连续快速触发时,队列已经大于1了,后续的触发被忽略了**。

举个例子:

- 第1个通知进来,队列长度是1,触发 displayNext
- 显示第1个通知,启动3秒的 setTimeout
- 在这3秒内你又点了几次按钮,队列已经变成 [msg2, msg3, ...]
- 但因为队列长度不为1,displayNext 没有再被调用
- 第一个通知消失后调用 displayNext,只显示 msg2
- msg3 及之后的还在队列里,但没人触发下一次显示

**所以问题的本质是:只有第一次显示时会触发流程,后续的队列项没人继续推进**

---

### ✅ 正确做法是:

**不管队列长度是多少,只要新加了通知,就尝试触发队列流程**,但要判断是否已经在处理中,避免重复触发。

你可以改成这样:

let queue = [];
let isProcessing = false;

function showNotification(msg) {
queue.push(msg);
if (!isProcessing) {
displayNext();
}
}

function displayNext() {
if (queue.length === 0) {
isProcessing = false;
return;
}

const msg = queue.shift();
notificationEl.textContent = msg;
notificationEl.style.display = 'block';

isProcessing = true;

setTimeout(() => {
notificationEl.style.display = 'none';
displayNext();
}, 3000); // 显示3秒后隐藏
}


---

### 🧪 补充说明

- 加了个 isProcessing 标志位,表示当前是否正在处理通知队列
- 每次调用 showNotification 都会检查是否需要触发 displayNext
- displayNext 会持续处理队列,直到清空
- 这样就能保证**通知一定按顺序排队显示,不会重叠**

我以前也踩过这个坑,关键是控制流程状态,不是单纯靠 setTimeout 延迟。调试看看队列和标志位变化就明白了。
点赞 11
2026-02-04 16:23
东方春依
问题出在你直接用了 setTimeout,但它没法精确控制动画完成的时机。建议用 CSS 动画结合 transitionend 事件来确保前一个通知完全消失后再显示下一个。

直接这样:
let queue = [];
let isShowing = false;

function showNotification(msg) {
queue.push(msg);
if (!isShowing) displayNext();
}

function displayNext() {
if (queue.length === 0) {
isShowing = false;
return;
}
isShowing = true;
const msg = queue.shift();
notificationEl.textContent = msg;
notificationEl.style.display = 'block';
notificationEl.style.opacity = 1;

setTimeout(() => {
notificationEl.style.opacity = 0;
notificationEl.addEventListener('transitionend', () => {
notificationEl.style.display = 'none';
displayNext();
}, { once: true });
}, 3000);
}

记得给 notificationEl 加上 CSS 动画,比如 transition: opacity 0.5s;。这样就能保证顺序不乱了。
点赞 12
2026-01-29 18:06