preface

Programming is often presented with correct business documentation or specifications for business processes, but actual development is riddled with thorns and exceptions, including exceptions to business use cases as well as technical exceptions. We have no alternative to exceptions to business use cases, and must require both implementor and user to provide reasonable solutions; The technical exceptions, however, have to be handled by our programmers, and that’s what I want to document. I’m going to split it into “Front-end Magic: Exceptions Are More than just try/ Catch” and “Front-end Magic: Call Stack, Treasure of Exception Instances” to describe built-in/custom exception classes that capture runtime exceptions/syntax exceptions/network request exceptions /PromiseRejection events. Information about what a call stack is and how to get it. Are you looking forward to it even before you start? Ok, everybody hold on to the handrail, the old driver is going to drive

The profile

This article will describe the following contents:

  1. Exception or error? How will it affect our code?
  2. What are the built-in exception types?
  3. Start writing your own exception types!
  4. Catch the runtime exception in Sync Code withtry/catchIt is enough.
  5. “Universal” exception catcherwindow.onerrorIs it really omnipotent?
  6. Promise. Reject Also throws exceptions, what to do?
  7. 404, such as network request abnormality really after sleep?

One. Exception or error? How will it affect our code?

When we learn Java, we are told that exceptions are different from errors. Exceptions do not cause the process to terminate and can be fixed (try/catch), but errors cause the process to terminate and cannot be fixed. When it comes to JavaScript, all we have to deal with is an exception (although the exception class name is Error or contains the Error word). The occurrence of an exception does not cause the JavaScript engine to crash, but only terminates the currently executing task. What do you mean by saying that an exception can only cause the current task to terminate? This involves the principle of Event Loop, and I will try to explain it in code.

<script>
  // 1. The current code block will be pushed into the task queue as a task, and the JavaScript thread will continuously extract the task from the task queue for execution;
  // 2. If an exception is reported during the execution of the task, and the exception is not captured and processed, the call stack will be thrown from the top to the bottom, and the execution of the current task will be terminated.
  // 3. The JavaScript thread will continue to extract the next task from the task queue and continue to execute.
  function a(){throw Error("test")}
  function b(){a()}
  b()
  console.log("Never executed!")
</script>
<script>
  // Next task
  console.log("You have you throw abnormal, I still execute!")
</script>Copy the code

What are the built-in exception types?

When it comes to built-in exception classes, the ancestor of Error must be mentioned first. All other built-in and custom classes must inherit from Error. These are just a few of its standard properties and methods

@prop {String}Name - The exception name @prop{String} message- Unusual messages for human reading @prop{Function} constructor- Type constructor @method toString(a):String- Displays abnormal informationCopy the code

Because there were too few standard attributes to provide more effective information for developers to locate exceptions and reconstruct accident scenes, browser manufacturers began adding their own attributes, which gradually became de facto standards.

@prop {String} fileName -The script in which the exception occursURI
@prop {number} lineNumber -The line number on which the exception occurred @prop {number} columnNumber -The column number where the exception occurred @prop {String} stack -Call stack information when an exception occurs,IE10@ is supported only when abovemethodToSource ():String - The content of the script where the exception occurredCopy the code

Additional giant hard still add the following two attributes

@prop {String} description -messageAlmost @prop {number} number -The number of the exception type. Jumbo sets a unique number for each exceptionCopy the code

So now I want to instantiate an Error object, just call Error() or new Error(); If you want to set message at the same time, change to Error(“test”) or new Error(“test”). The Error constructor signature actually looks like this

@constructor
@param {String=} message- setmessageAttribute @param {String=} fileName- setfileNameAttribute @param {number=} lineNumber- setlineNUmberattributeCopy the code

Now let’s take a look at what types of exceptions are built in!

  1. EvalError, the calleval()Is deprecated for backward compatibility only
  2. InternalError, JavaScript engine internal exception, FireFox only provided!
  3. RangeErrorOccurs when a function argument is out of bounds, as inArray.Number.toExponential.Number.toFixedandNumber.toPrecisionTime entry is illegal.
  4. ReferenceError occurs when an undeclared variable is referenced
  5. SyntaxError, a SyntaxError occurred during parsing
  6. TypeError, when the value is not of the expected type,null.f()Also report this error
  7. URIErrorOccurs when an invalid URI is passed to the global URI handler, as indecodeURIComponent('%'), i.e.,decodeURIComponent.decodeURI.encodeURIComponent.encodeURI

Write your own exception types!

There’s been a lot of discussion on StackOverflow about how to customize exception types so we can just do it, right

function MyError(message, fileName, lineNumber){
  if (this instanceof MyError);else return new MyError(message, fileName, lineNumber)
  this.message = message || ""
  if (fileName){ this.fileName = fileName }
  if (lineNumber){ this.lineNumber = lineNumber }
}

var proto = MyError.prototype = Object.create(Error.prototype)
proto.name = "MyError"
proto.constructor = MyErrorCopy the code

The CLJS implementation is as follows

(defn ^export MyError [& args]
  (this-as this
    (if (instance? MyError this)
      (let [ps ["message" "fileName" "lineNumber"]
            idxs (-> (min (count args) (count ps)) range)]
        (reduce
          (fn [accu i]
            (aset accu (nth ps i) (nth args i))
            accu)
          this
          idxs))
      (apply new MyError args))))

(def proto
  (aset MyError "prototype" (.create js/Object (.-prototype Error))))
(aset proto "name" "MyError")
(aset proto "constructor" MyError)Copy the code

Catch “runtime exception” in “sync code” withtry/catchIt is enough

To avoid the risk of normal code being skipped due to an exception, try/catch is used to catch and handle exceptions.

try{
  throw Error("unexpected operation happen...")}catch (e){
  console.log(e.message)
}Copy the code

CLJS writing

(try
  (throw (Error. "unexpected operation happen...")
  (catch e
         (println (.-message e)))))Copy the code

Most of the time we would think that writing would be done, but try/catch can only catch “runtime exceptions” in “synchronized code.” 1.” Synchronous code “means that it cannot get exceptions from asynchronous code such as setTimeout and Promise, that is, try/catch can only catch exceptions from the current task, and asynchronous code such as setTimeout is executed in the next EventLoop.

// True capture can not ah pro ~!
try{
  setTimeout(function(){
    throw Error("unexpected operation happen...")},0)}catch(e){
  console.log(e)
}Copy the code

2.” runtime exception “refers to a non-syntaxerror, which is a SyntaxError that cannot be caught because it was reported when parsing JavaScript source code

// invalid identifier a->b
try{
  a->b = 1
} catch(e){
  console.log(e)
}Copy the code

It’s tempting to ask, “What about asynchronous code exceptions? What about syntax exceptions?” Before we answer that question, let’s deviate a little and dig a little deeper into the nature of the throw statement.

throwWhat can I do with it?

In general we throw an instance of Error or a subclass of Error(such as throw Error()), but we throw any type of data (such as throw 1,throw “test”,throw true, etc.). But even though we can throw arbitrary types of data, we insist on throwing instances of Error or its subclasses. Why is that?

try{
  throw "unexpected operation happen..."
} catch(e){
  console.log(e)
}

try{
  throw TypeError("unexpected operation happen...")}catch(e){
  if ("TypeError" == e.name){
    // Do something1
  }
  else if ("RangeError" == e.name){
    // Do something2}}Copy the code

The reason is obvious – the more complete information you provide when an exception occurs, the easier it is to track down and locate the problem.

“Universal” exception catcherwindow.onerrorIs it really omnipotent?

It is obviously not practical (and there are performance issues) to write try/catch everywhere an exception can occur, even if it is verbose like Java, where we constantly declare throws and then handle exceptions at the top level. So where is the corresponding top-level exception handling entry in JavaScript? There is no mistake, just window.onerror. Look at the method signature

@descriptionWindow. onerror @param {string} message -Exception message "@param {string} source  -Of the script in which the exception occurredURI
@param {number} lineno  -The script number on which the exception occurred @param {number} colno   -The script column where the exception occurred @param {?Error} error   - ErrorInstance,SafariandIE10Does not have this argument inCopy the code

At this point we can catch through it in addition to try/catch can catch exceptions, but also catch setTimeout and other asynchronous code exceptions, syntax errors.

window.onerror = function(message, source, lineno, colno, error){
  // Do something you like.
}

setTimeout(function(){ throw Error("oh no!")},0)
a->b = 1Copy the code

Is that enough? If onError returns true, the exception will not continue to be thrown up (otherwise it will become an Uncaught Error).

// there is no problem with exception, because I can't see ^_^
window.onerror = function(){return true}Copy the code

Now back to the question of the title, is onError enough to catch all exceptions? The answer is no (oh my god, how much longer are we going to do this ~ 0 ~)

  1. In Chrome, onError can catch exceptions reported by cross-domain scripts, but it is reported uniformlyScript Error. To get the correct error information, cross-domain resource sharing CORS must be configured.
  2. window.onerrorIn fact, the event bubble mechanism is used to catch exceptions and is only triggered during the bubble phase, so non-bubbling exceptions such as network request exceptions cannot be caught.
  3. Promise. Reject An exception that is not caught,window.onerrorThere’s nothing I can do about it.

Reject also throw exception, how to do?

Dealing with complex asynchronous process control through Promises is handy, but what if there is an exception or the state of the Promise instance changes to Rejected?

How does a Promise signal that an exception has occurred?

The initial state of the Promise instance is Pending and the exception is Rejected. The action that causes the state to change from pending to Rejected is

  1. callPromise.rejectClass method
  2. Called in the factory methodrejectmethods
  3. Throw an exception in a factory method or then callback function
1 / / way
Promise.reject("anything you want")

2 / / way
new Promise(function(resolve, reject) { reject("anything you want")})3 / / way
new Promise(function{ throw "anything you want" })
new Promise(function(r) { r(Error("anything you want" ) }).then(function(e) { throw e })Copy the code

When a Promise instance changes from Pending to Rejected, it is either caught and processed or it continues to be thrown until it becomes an Uncaught(in Promise) Error.

Before the exception occurscatchoff

If we had called the catch method to catch the exception before it happened, we would be fine

new Promise(function(resolve, reject){
  setTimeout(reject, 0)
}).catch(function(e){
  console.log("catch")
  return "bingo"
}).then(function(x){
  console.log(x)
})

/ / echo bingoCopy the code

Top-level exception handling that is Promise specific

If we do not call the catch method before the exception occurs, we can still catch the exception through the unhandledrejection event of the window

window.addEventListener("unhandledrejection".function(e){
  // Event adds a new attribute
  // @prop {Promise} Promise - The Promise instance whose state is Rejected
  / / @ prop {String | Object} "reason - the content of the anomaly information or rejected

  // Will prevent the exception from continuing to be thrown, so that Uncaught(in promise) Error does not occur
  e.preventDefault()
})Copy the code

Of latecatch

Since a Promise instance can subscribe asynchronously to its state changes, that is, it can register a catch handler asynchronously, we have already thrown an Uncaught(in Promise) Error, but we can still handle it

var p = new Promise(function(resolve, reject){
  setTimeout(reject, 0)
})
setTimeout(function(){
  p.catch(function(e){
    console.log("catch")
    return "bingo"})},1000)Copy the code

Alternatively, you can listen for the asynchronous registration of a catch handler through the RejectionHandled event of the window

window.addEventListener("rejectionhandled".function(e){
  // Event adds a new attribute
  // @prop {Promise} Promise - The Promise instance whose state is Rejected
  / / @ prop {String | Object} "reason - the content of the anomaly information or rejected

  // Uncaught(in promise) Error has been thrown, so this sentence does not mean anything
  e.preventDefault()
})Copy the code

Note: An asynchronous catch will only raise this event if an Uncaught(in Promise) Error is thrown.

Seven.404, such as abnormal network request really after sleep?

window.addEventListener("error".function(e){
  // Do something
  console.log(e.bubbles) / / echo false
}, true)Copy the code

Because network request exceptions do not bubble up, they must be caught during the Capture phase. However, another problem is that this method can not accurately determine whether the HTTP status of the exception is 404 or 500, so it still needs to be analyzed with the server log.

conclusion

For exceptions and how to catch exceptions just a handful of front-end intelligent monitoring knowledge, stay tuned for subsequent a handful of other knowledge “in the front hall of magic – the call stack, abnormal instance treasure” : D respect the original, reproduced please indicate from: www.cnblogs.com/fsjohnhuang… ^_^ fat John

reference

Developer.mozilla.org/en-US/docs/… Stackoverflow.com/questions/8…

Scan this article if you find it interesting! Donation mutual encouragement!