如何让浏览器原生函数使用重定义的Promise类?
问题
通过猴子补丁重定义全局Promise类后,浏览器的fetch、document.hasStorageAccess等原生函数返回的Promise并不会使用这个自定义类。示例代码如下:
Promise = class extends Promise { constructor(executor) { console.log("Promise created"); super(executor); } } console.log("Non-native promise"); Promise.resolve(1); // 会打印"Promise created" console.log("Native promise"); fetch("https://httpbin.org/delay/1"); // 无打印 console.log("Native promise"); document.hasStorageAccess(); // 无打印
在浏览器环境中,Promise.resolve创建的实例会走自定义构造函数,但原生API返回的Promise完全不受影响(Node.js中fetch的行为取决于具体实现,可能不同)。请问有没有办法让这些原生函数也使用自定义的Promise类?
答案
浏览器原生API内部直接调用底层原生Promise实现,不会读取全局Promise变量,所以单纯重定义全局Promise无法影响它们。可行的方案是逐个包装原生API,将其返回的原生Promise转换为自定义Promise实例:
包装fetch
const originalFetch = window.fetch; window.fetch = (...args) => { return new Promise((resolve, reject) => { originalFetch(...args).then(resolve).catch(reject); }); };
包装document.hasStorageAccess
const originalHasStorageAccess = document.hasStorageAccess; document.hasStorageAccess = function(...args) { return new Promise((resolve, reject) => { originalHasStorageAccess.call(this, ...args).then(resolve).catch(reject); }); };
这样调用原生API时,它们返回的原生Promise会被包装成自定义Promise实例,从而触发你重定义的构造函数逻辑。
需要注意:这种方法需要手动包装所有需要拦截的原生API,没有通用的钩子可以一次性修改所有原生Promise的创建逻辑——因为浏览器原生API的Promise创建逻辑是封装在底层实现中的,并未对外暴露可修改的接口。
内容的提问来源于stack exchange,提问作者Heiko Theißen
相关产品推荐
相关产品推荐

