Skip to content

Reflect反射的兼容问题

页面中执行 fet-block-logic.js,sentry监控会发现忽然上涨如下这样的报错:

主要有2个问题:

  1. Falled to construct "XMLHttpRequest: Please use the 'new' operator, this DoM object constructor cannot be called as a function
  2. t._resetXhrUnset is not a function, t._resetXhrToUnset is undefined

问题1看起来像是有人通过直接函数调用的方式使用了 window.XMLHttpRequest,而window.XMLHttpRequest是构造函数,需要使用 new 来调用。 然而为什么只有我们的代码发布后才会产生这种报错呢?这说明肯定也跟我们代码有关。

问题2看起来是我们的自己实现的FetXMLHttpRequest类中,调用自身方法时候,报了不存在该方法。仔细回看了下代码,我们代码都是在自己的class内部通过 this 来调用,理论上不应该出现这种错误。难道是有人在使用我们的XHR class的时候,强行改掉了我们某些函数的this指向。

下面我们来分析这2个问题。

分析问题1

DANGER

Falled to construct "XMLHttpRequest: Please use the 'new' operator

该问题看起来主要发生在 chrome50及其以下的安卓机器,于是我们找到一台 chrome 43的安卓5进行复现。发现确实可以复现。复现后开始debug打日志,看看到底是哪一个步骤出现问题。最终找到

解决rollup编译后类继承时的机型兼容问题

sentry部分安卓5机型(都是chrome小于等于50内核)出现报错:

Failed to construct 'XMLHttpRequest': Please use the 'new' operator

部分ios小于等于13机型报出:

function _resetXhrUnset is undefined

经过实际分析,发现:

  • 安卓报错原因,是因为其不支持 Reflect但是 rollup 构建结果判定时

找到真正的 XHR

js
function getNativeXHr() {
    let xhrProto = window.XMLHttpRequest.prototype
    while(Object.getPrototypeOf(xhrProto) !== XMLHttpRequestEventTarget.prototype) {
        xhrProto = Object.getPrototypeOf(xhrProto);
    }
    return xhrProto.constructor
}

为了防止上述函数死循环,我们这样进行xhrProto的兜底处理:

js
function getNativeXHr() {
    let xhrProto = window.XMLHttpRequest.prototype
    while(Object.getPrototypeOf(xhrProto) !== XMLHttpRequestEventTarget.prototype) {
        xhrProto = Object.getPrototypeOf(xhrProto);
        if (!xhrProto) break;
    }
    return xhrProto?.constructor
}