Frontend Development 21 min read

How to Capture, Diagnose, and Fix Script Errors in Front‑End Projects

This article explains why script errors appear in front‑end pages, describes methods such as enabling CORS, using try‑catch wrappers, handling JSONP and AJAX failures, and outlines logging, statistical analysis, and monitoring techniques to locate and resolve badjs issues effectively.

WecTeam
WecTeam
WecTeam
How to Capture, Diagnose, and Fix Script Errors in Front‑End Projects

Preface

In daily front‑end work, badjs is a common problem. Besides obvious errors in our own JavaScript, errors from dependent resources (external scripts, interface failures) also generate

script error

messages that are hard to locate.

Front‑end developers not only implement business features but also operate page‑quality monitoring; badjs monitoring and anomaly analysis are key tasks. This article shares methods and ideas for collecting, locating, aggregating, and analyzing

script error

incidents.

Origin of script error

Pages often host static resources (js, css, images) on third‑party CDNs or rely on external assets. When a third‑party JavaScript throws an exception, the same‑origin policy hides detailed error information and returns a generic

script error

.

WebKit source code (simplified):

<code>bool ScriptExecutionContext::sanitizeScriptError(String&amp; errorMessage, int&amp; lineNumber, String&amp; sourceURL) {
  KURL targetURL = completeURL(sourceURL);
  if (securityOrigin()-&gt;canRequest(targetURL)) return false;
  // Non‑same‑origin: replace error info with default values
  errorMessage = "Script error.";
  sourceURL = String();
  lineNumber = 0;
  return true;
}

bool ScriptExecutionContext::dispatchErrorEvent(const String&amp; errorMessage, int lineNumber, const String&amp; sourceURL) {
  EventTarget* target = errorEventTarget();
  if (!target) return false;
  String message = errorMessage;
  int line = lineNumber;
  String sourceName = sourceURL;
  sanitizeScriptError(message, line, sourceName);
  ASSERT(!m_inDispatchErrorEvent);
  m_inDispatchErrorEvent = true;
  RefPtr<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line);
  target-&gt;dispatchEvent(errorEvent);
  m_inDispatchErrorEvent = false;
  return errorEvent-&gt;defaultPrevented();
}
</code>

Common solutions

Two typical ways to obtain detailed error logs for external

script error

:

1. Enable CORS (Cross‑Origin Resource Sharing)

a) Add

crossorigin="anonymous"

attribute to the script tag:

<code>&lt;script src="http://domain/path/*.js" crossorigin="anonymous"&gt;&lt;/script&gt;</code>

When

crossorigin="anonymous"

is present, the browser fetches the script anonymously, without sending cookies or other credentials.

b) The static server must return the appropriate CORS header:

<code>Access-Control-Allow-Origin: *</code>

After these two steps,

window.onerror

can capture detailed error information from cross‑origin scripts.

2. Use try‑catch wrappers

While CORS solves many cases, large enterprises often have many domains and cannot configure CORS everywhere, and some external resources may not support it. In such cases, wrap calls to external resources with

try…catch

and report errors when caught:

<code>function invoke(obj, method, args) {
  try {
    return obj[method].apply(this, args);
  } catch (e) {
    reportBadjs(e); // report the error
  }
}
</code>

Case studies

1) For resources we control, configure CORS headers and add

crossorigin="anonymous"

to obtain full stack traces.

2) JSONP request issues:

a) Interface exception – a 302 redirect to an error page results in

script error

. Since the response cannot be parsed, we report the error based on the

onload

callback:

<code>// onload handler reports server error when callback is missing
el.onload = el.onreadystatechange = function() {
  if (!cgiloadOk) {
    report(cgi, 'servererror');
  }
};
window.newFunction = function(rsp) {
  cgiloadOk = true;
  window.originFunction(rsp);
};
</code>

b) Non‑standard JSON response also triggers

script error

. Convert the API to return a JSON string and parse it inside a

try…catch

block, reporting the raw data on failure:

<code>let sc = document.createElement('script');
let head = document.getElementsByTagName('head')[0];
sc.setAttribute('charset', charset || 'utf-8');
sc.src = url;
head.appendChild(sc);
window.newFunction = function(text) {
  // try‑catch to capture parse errors
  try {
    let jsonStr = JSON.parse(text);
  } catch (e) {
    reportBadjs(text); // report the error data
  }
};
</code>

JSONP only supports GET and cannot obtain HTTP status codes on error.

3) AJAX requests provide status codes and response data, allowing distinction between network errors and data‑parse errors:

<code>let xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
  if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
    let str = xmlHttp.responseText;
    try {
      let json = JSON.parse(jsonstr);
      // render data
    } catch (e) {
      report(jsonstr, 'data parse err'); // report raw data
    }
  } else if (xmlHttp.readyState == 4) {
    report(cgi, xmlHttp.status); // report redirect or other status
  }
};
xmlHttp.open('GET', cgi, true);
xmlHttp.send();
</code>

This method can capture error data and status, but the API must support CORS.

4) When external resources cannot set CORS headers, wrap their calls with

try…catch

and report exceptions.

Common jQuery/Zepto usage can be wrapped as:

<code>function myBind(obj) {
  let o = {
    'type': 'click', // event type
    'src': '.',      // selector
    'fun': function() {}, // method
    'isStop': true   // stop propagation
  };
  for (let i in obj) {
    o[i] = obj[i];
  }
  if (typeof o.src === 'string') {
    o.$src = $(o.src);
  }
  $(o.src).off(o.type).on(o.type, function(e) {
    try {
      o.fun.apply(o, [e, $(this)]);
    } catch (ea) {
      reportBadjs(ea.stack); // report error
    }
    if (o.isStop) {
      return false;
    }
  });
}
</code>

Alternative analysis ideas

When external resources lack CORS headers and generate

badjs

or page‑refresh errors, precise location is difficult. However, auxiliary methods can help infer the cause and page health.

1. Client‑side analysis

a) Channel proportion: Analyze the

ua

field of reported

script error

logs to see the distribution across WeChat, SQ, H5, etc. Sudden spikes in a specific channel may indicate bot traffic.

During an anomaly, the channel distribution changes dramatically, revealing the problematic source.

b) UA proportion: When a new version is released, a sudden UA dominance may indicate compatibility issues with certain browsers.

2. Combine with user‑behavior analysis

a) Record user clicks (mobile example):

<code>let eventElemArr = [];
document.body.addEventListener('touchend', function(e) {
  // record tag and class
  eventElemArr.push([e.target.tagName, e.target.className].join('_'));
}, false);
window.onerror = function(msg, url = '', line = '', col = '', error = '') {
  let errStr = [JSON.stringify(msg), url, line, col, error, eventElemArr.join('|')].join('$');
  report(errStr);
  return false;
};
</code>

By correlating the trace ID generated on page entry with backend logs, we can link a

badjs

event to the full request trace.

<code>// generate traceid
window.initTraceid = { bizId: '', operateId: '' };
(function(){
  window.initTraceid.traceid = genTraceid(window.initTraceid);
})();
window.onerror = function(msg, url = '', line = '', col = '', error = '') {
  let errStr = [JSON.stringify(msg), url, line, col, error, window.traceid || ''].join('$');
  report(errStr);
  return false;
};
function myRequest(url) {
  url = url.addParam({ traceid: window.traceid || '' });
  request(url);
}
</code>

3. On‑site reproduction

3.1 Record video: Capture screen snapshots at ~25 fps using

canvas

or record DOM mutations. When a

script error

occurs, upload the cached images for later playback.

3.2 Record DOM changes via

MutationObserver

, then replay the mutation log together with the error.

Log reporting, aggregation, analysis and monitoring

After covering the origin, solutions, case studies, and alternative ideas, we finally discuss log handling.

1. Log reporting

<code>// Global onerror for page exceptions
window.onerror = function(msg, url, line, col, error) {
  let excludeList = ['WeixinJSBridge'];
  let errStr = obj2str(msg) + (url ? ';URL:' + url : '') + (line ? ';Line:' + line : '') + (col ? ';Column:' + col : '');
  for (let item of excludeList) {
    if (errStr.indexOf(item) > -1) return;
  }
  let g = new Image();
  g.src = reportUrl + errStr + '&t=' + Math.random() + (window.traceid ? '&traceid=' + window.traceid : '');
  return false;
};
// Promise rejection handling
window.addEventListener('rejectionhandled', event => {
  window.onerror('', '', '', '', event.reason);
});
// Vue error handling
Vue.config.errorHandler = function(err, vm, info) {
  window.onerror(info, '', '', '', err);
};
</code>

Server‑side collection also records IP, user info, traceid, network type, UA, timestamp, etc.

2. Log aggregation and analysis

a) Quantity view – real‑time error count with alert rules.

b) Error‑message aggregation – shows most frequent messages.

c) Detailed log view – includes channel, network, user, UA, and traceid for deep investigation.

d) Multi‑dimensional analysis (carrier, device, OS, channel, etc.) to spot patterns.

3. Error monitoring

We separate ordinary

badjs

from

servererror

. Ordinary

badjs

are analyzed via logs and dashboards;

servererror

alerts are routed to the responsible API owners. Each page automatically generates two keys (badjs and servererror). Alerts are configured with yellow (warning) and red (critical) levels, triggering notifications to owners.

Dashboard views show spikes of

badjs

after a release, allowing rapid rollback and fix.

When a

servererror

alert fires, the reported interface information enables quick identification of the problematic API.

CORSerror handlingscript errortraceidfrontend monitoringbadjs
WecTeam
Written by

WecTeam

WecTeam (维C团) is the front‑end technology team of JD.com’s Jingxi business unit, focusing on front‑end engineering, web performance optimization, mini‑program and app development, serverless, multi‑platform reuse, and visual building.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.