如何让Polyfill保持不可变?Shopify商店Promise原型异常求助
解决Promise.prototype自定义属性被delete移除的问题
问题分析
你之前的两种方案无效的原因:
- 示例1只设置了
writable: false,但configurable默认是true,而delete操作仅受configurable属性控制,所以依然能被删除。 - 示例2的
Object.freeze如果是在第三方代码覆盖原型之后执行,或者第三方直接替换了整个Promise.prototype对象,那么冻结原来的原型就起不到作用。
可行方案
1. 定义属性时显式设置configurable: false
这是最直接的方法,给自定义polyfill属性加上不可配置的限制,阻止delete操作:
// 正确定义onFinally polyfill,阻止被delete Object.defineProperty(Promise.prototype, 'onFinally', { value: function(callback) { return this.then( result => Promise.resolve(callback()).then(() => result), error => Promise.resolve(callback()).then(() => { throw error; }) ); }, writable: true, // 可选:如果不需要修改实现,可设为false enumerable: false, // 保持与Promise内置方法一致的不可枚举特性 configurable: false // 核心:阻止delete移除该属性 });
2. 用Proxy拦截delete操作(应对原型被替换的情况)
如果第三方代码会直接替换整个Promise.prototype,可以用Proxy包装原型,拦截delete和原型替换:
const originalPromise = Promise; // 拦截Promise的原型访问和修改 Object.defineProperty(globalThis, 'Promise', { get() { return originalPromise; }, set(newPromise) { // 如果第三方试图替换Promise,我们给它的原型也加上Proxy拦截 if (newPromise.prototype) { newPromise.prototype = new Proxy(newPromise.prototype, { deleteProperty(target, prop) { // 保护我们的polyfill属性 if (prop === 'onFinally') return false; return delete target[prop]; } }); } originalPromise = newPromise; return true; }, configurable: false }); // 提前定义polyfill Object.defineProperty(Promise.prototype, 'onFinally', { value: function(callback) { /* 实现同上 */ }, enumerable: false, configurable: false });
3. 自定义Promise类(彻底隔离原生原型影响)
完全不依赖原生Promise.prototype,自己封装继承原生Promise的类,业务代码改用这个类:
class ShopPromise extends Promise { onFinally(callback) { return this.then( res => ShopPromise.resolve(callback()).then(() => res), err => ShopPromise.resolve(callback()).then(() => { throw err; }) ); } } // 业务中所有用到Promise的地方替换为ShopPromise ShopPromise.resolve('data') .then(res => console.log(res)) .onFinally(() => console.log('completed'));
这种方法彻底避免了原生原型被修改的影响,最稳定。
内容的提问来源于stack exchange,提问作者Maxim Secret
相关产品推荐
相关产品推荐

