需包装因vibrate()同步返回但无完成通知,故用Promise+setTimeout模拟结束时机并处理权限/兼容性问题;基础版校验支持与权限后按总时长resolve,增强版支持AbortSignal取消。

设备振动 API(navigator.vibrate())本身是同步的,不返回 Promise,也不触发回调,因此需要手动包装成 Promise 来统一异步流程、支持 await 和错误处理。
为什么需要包装?
原生 vibrate() 方法立即返回 true(表示调用成功)或 false(权限被拒/不支持),但不反映实际振动是否完成或是否被系统静音/中断。它也没有完成通知机制。为实现“等待振动结束再执行后续逻辑”,需结合定时器模拟完成时机,并捕获可能的失败场景。
基础 Promise 包装(按持续时间等待)
最常用方式:根据传入的振动时长(毫秒或数组),用 setTimeout 模拟“完成”时机,并在开始前校验环境支持与权限:
function vibrateAsync(pattern) {
return new Promise((resolve, reject) => {
// 检查 API 是否可用
if (!navigator.vibrate) {
return reject(new Error('Vibration API not supported'));
}
// 尝试触发振动(仅作权限试探;部分浏览器需用户交互后才允许)
const success = navigator.vibrate(pattern);
if (!success) {
return reject(new Error('Vibration permission denied or unavailable'));
}
// 计算总持续时间(兼容 number 或 [ms1, ms2, ...])
const totalMs = Array.isArray(pattern)
? pattern.reduce((sum, t) => sum + t, 0)
: pattern;
// 等待振动“逻辑完成”
setTimeout(() => resolve(), totalMs);
});
}
// 使用示例
async function playFeedback() {
try {
await vibrateAsync(200); // 振动 200ms
console.log('✅ Vibration done');
} catch (err) {
console.warn('⚠️', err.message);
}
}
增强版:支持取消与更准的状态反馈
原生 API 不可取消,但可封装一个带“软取消”语义的版本(即提前 reject,不等待):
立即学习“Java免费学习笔记(深入)”;
function vibrateAsync(pattern, { signal } = {}) {
return new Promise((resolve, reject) => {
if (signal?.aborted) {
return reject(new DOMException('Aborted', 'AbortError'));
}
if (!navigator.vibrate) {
return reject(new Error('Vibration API not supported'));
}
const success = navigator.vibrate(pattern);
if (!success) {
return reject(new Error('Vibration failed: permission denied or unsupported'));
}
const totalMs = Array.isArray(pattern)
? pattern.reduce((sum, t) => sum + t, 0)
: pattern;
const timeoutId = setTimeout(resolve, totalMs);
// 监听 abort
signal?.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new DOMException('Aborted', 'AbortError'));
}, { once: true });
});
}
// 使用 AbortController 取消
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 100);
vibrateAsync(500, { signal: ctrl }).catch(console.error);
注意事项与兼容性提示
- 必须由用户手势触发:首次调用需在 click/tap 等事件处理函数中,否则多数浏览器会静默失败
- 静音模式下可能无效果:iOS Safari 完全禁用振动(即使代码执行成功),Android 多数厂商也遵循系统静音策略
-
无真实完成事件:Promise 的
resolve仅代表“预期结束时间到达”,不是硬件级确认 -
pattern 数组含义:
[200, 100, 300]表示「振 200ms → 停 100ms → 振 300ms」,总耗时 = 所有值之和


















