問題背景
在開發基於 Vite 的 Web 應用時,使用 Promise.allSettled 方法時發現,在部分舊版安卓設備(如小米8,Android 8.1.0)上運行時,控制枱報錯 TypeError: Promise.allSettled is not a function。該問題導致應用功能異常,影響用户體驗。
受影響的設備環境
- 設備:小米8(Android 8.1.0)
- 瀏覽器/WebView:Chrome 60~68(Android 8.1.0 默認瀏覽器內核)
- 問題現象:
Promise.allSettled未定義,代碼執行中斷。
問題原因分析
1. 瀏覽器兼容性不足
Android 8.1.0 默認瀏覽器或 WebView 基於 Chrome 60 左右,而 Promise.allSettled 是 ES2020(ES11)引入的特性,支持環境為:
- Chrome ≥76
- Firefox ≥71
- Safari ≥13.1
- Edge ≥79
舊版瀏覽器未實現該 API,導致代碼報錯。
2. Vite 默認構建策略
Vite 默認以現代瀏覽器為構建目標(如支持 ES 模塊的瀏覽器),生成的代碼可能包含未降級的 ES2020+ 語法,舊版瀏覽器無法解析。
3. 未正確注入 Polyfill
項目中未對舊版瀏覽器提供 Promise.allSettled 的 Polyfill 支持,導致目標環境無法識別該 API。
解決方案
通過 @vitejs/plugin-legacy 插件配置,針對舊版瀏覽器生成兼容代碼並注入必要的 Polyfill。
步驟 1:安裝依賴
npm install @vitejs/plugin-legacy --save-dev
步驟 2:配置 vite.config.ts
import { defineConfig } from "vite";
import legacy from "@vitejs/plugin-legacy";
export default defineConfig({
plugins: [
legacy({
// 指定目標瀏覽器範圍
targets: ["defaults", "not IE 11", "chromeAndroid>=52", "iOS>=13.1"],
// 為現代瀏覽器添加必要的 Polyfill(此處需結合業務場景)
modernPolyfills: ["es/promise", "es/array"],
}),
],
});
配置項説明
-
targets
定義需要支持的瀏覽器版本範圍:defaults:兼容所有瀏覽器廠商的最新穩定版本。
not IE 11:排除 IE 11。
chromeAndroid>=52:兼容 Chrome Android 52 及以上。
iOS>=13.1:兼容 iOS Safari 13.1 及以上。
-
modernPolyfills
為現代瀏覽器手動添加 Polyfill(需結合代碼中使用的特性)。例如:es/promise:提供 Promise 相關 Polyfill。
es/array:提供 Array 相關方法(如 Array.prototype.includes)。
步驟 3:驗證 Polyfill 注入
構建項目後,檢查生成的 HTML 文件是否包含舊版代碼塊:
<script nomodule src="/assets/legacy.js"></script>
<script type="module" src="/assets/modern.js"></script>
舊版瀏覽器(如 Android 8.1.0)會加載 legacy.js,其中包含降級代碼和 Polyfill。
驗證測試
-
真機測試
在小米8(Android 8.1.0)設備中:清除瀏覽器緩存。
打開應用,檢查控制枱是否報錯。
執行以下代碼驗證 Promise.allSettled:
const promises = [
Promise.resolve("成功"),
Promise.reject("失敗"),
];
Promise.allSettled(promises).then((results) => {
console.log(results);
});
預期輸出:
[
{ status: "fulfilled", value: "成功" },
{ status: "rejected", reason: "失敗" },
]
- 瀏覽器兼容性檢查
使用 Can I Use 或 Babel 瀏覽器兼容性表 確認目標瀏覽器是否支持配置的 Polyfill。
總結
- 問題核心
舊版瀏覽器對 ES2020+ 特性支持不足,需通過構建工具提供降級代碼和 Polyfill。 - 解決方案要點
精準配置瀏覽器範圍:通過 targets 明確兼容範圍,避免過度 Polyfill。
按需注入 Polyfill:結合 modernPolyfills 和 additionalLegacyPolyfills 按需覆蓋未自動檢測的 API。
構建策略分離:為現代和舊版瀏覽器生成兩套代碼,平衡性能和兼容性。
- 最佳實踐
測試覆蓋:在真機和模擬器中測試所有目標瀏覽器。
監控構建體積:避免因 Polyfill 過多導致舊版代碼體積膨脹。
動態加載 Polyfill:對極少數舊版用户,可考慮按需動態加載 Polyfill。
附錄
參考文檔
- Vite 官方文檔 - @vitejs/plugin-legacy
- core-js Polyfill 列表
- Babel 瀏覽器兼容性配置