This article is mainly in accordance with the JS advanced program version 4 error handling and debugging order to write
Try catch can catch errors. What about promise.reject()?
Why await with try catch?
When does try catch work
When to catch an error with a try catch
Conclusion:
Async code cannot be caught, so promise.reject() errors cannot be caught, and promises deliberately encapsulate asynchronous behavior. 2. A try catch catches the result of a promise's reject() state. It must be thrown when the main thread execution has entered a try catch, but the try catch has not yet finished. 4. You should only catch an error if you know exactly what to do next.Copy the code
Summary of this article, really very fine, step by step with the walk, probably took a week, so it’s really worth a look, like it on the collection, I will continue to work hard!! Blunt!
Why should errors be caught and handled
By default, all browsers hide error messages. One reason is that this information is of little use to anyone other than the developer, and another reason is the inherent nature of web pages that report errors during normal operation.
When a JavaScript script error occurs on a web page, different browsers handle it in different ways and only output it in the browser. A good error handling policy can let users know what happened and prevent user loss. To do this, you must understand the various ways in which JavaScript errors can be caught and handled
Where do mistakes usually occur
PC: All modern desktop browsers expose errors through the console, meaning that the PC can catch errors on the console
Mobile: Mobile browsers do not provide a console interface directly on the device. However, there are ways to check for errors on mobile devices – I recommend the VConsole package here
How does it work? Read my article: juejin.cn/post/692241… In case any of you farts get lost, let me do this first
Basic introduction to try catch
3.1. The emergence of try catch, one of the methods to handle exceptions
Any code that can go wrong should be placed in the try block, and any code that handles errors should be placed in the catch block
try {
// Possible error code
} catch (e) {
// What do I do when something goes wrong
}
Copy the code
3.2 A try or catch block cannot prevent a finally block from executing
3.2.1 When a method that does not exist in the Window is called, an error must be reported. In this case, finanlly returns
try {
window.someNonexistentFunction();
console.log('try')}catch(e) {
console.log(e, 'catch')}finally {
console.log('finally')}Copy the code
3.2.2 There was no error, and at this time finanlly returned
try {
console.log('try')}catch(e) {
console.log(e, 'catch')}finally {
console.log('finally')}Copy the code
3.2.3 What can we do with Finally?
1. For example, loading must be cancelled, no matter whether I reported an error or not. Like doing some cleanup, some destructionCopy the code
3.3 A return statement cannot prevent finally execution
When a return is encountered, it usually exits the stack, but finally is still executed here
function testFinally(){
try {
return 2;
} catch (error){
return 1;
} finally {
return 0; }}console.log(testFinally());
Copy the code
How do try catches catch errors? When can errors be caught (It is very important
)
The exception caught by a try catch must be thrown when the main thread has entered the try catch, but the catch has not yet finished. Exceptions can only be caught in
4.1 Before a try catch (uncatchable
)
See? 6666 is not printed, such as a syntaxError, because an exception is reported during the syntax check phase and cannot be caught before the thread has entered the try catch block
4.2 Ongoing try catch (To capture the
)
try {
window.someNonexistentFunction();
} catch(e){
console.log("error",e);
}
console.log('I'm going to execute.')
Copy the code
That’s when you catch it
4.3 Ongoing try catch (Important: cannot be captured
)
try {
console.log('try it')
setTimeout(() = > {
console.log('setTimeOut in a try')
window.someNonexistentFunction(); // Becomes an uncaught error
}, 0)}catch (e) {
console.log('error', e)
}
setTimeout(() = > {
console.log('I'm going to execute.')},100)
Copy the code
There is no catch, because the try catch is synchronous. (setTimeOut is used to simulate asynchron, because it has the nature of delay.)
When js runs to setTimeOut inside a try,setTimeOut goes to the setTimeOut thread, and after 0 seconds to the Task queue,setTimeOut goes to the setTimeOut outside the try catch. The second setTimeOut also goes to the setTimeOut thread for 100/1000 seconds and then to the Task Queue after the first setTimeOut thread
So the order of execution is try catch, and the synchronization code, after the main stack is finished, goes to the Task Queue to see if there is anything to execute, and the task queue is first in, first out, in the order shown in the picture
This example is another reason why a try catch fails to catch a promise.resolve error
Eventloop is involved here, which I’ll cover next time
4.4 Exception capture of Promise
If the callback function is not set, errors thrown inside a Promise are not reflected outside.
Two ways to catch errors inside promises and one way to catch errors after a reject callback
1. Promise.prototype. Then () reject callback 2. Promise.prototype. Catch ()Copy the code
1. Combine async/await and try... catchCopy the code
4.4.1 Promise.prototype.then() capture — reject callback function
Features:
1. Unable to catch an exception in the resolve() callback, an infinite chain call to the then callback is required to catch exception 2. Subsequent THEN operations cannot be interruptedCopy the code
Case 1 is caught in the second Reject callback and, if there is an error, in the reject callback in the next THEN
const createPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('promise')},1000)
})
createPromise.then(res= > {
console.log(res, 'resolved');
}, res= > {
console.log(res, 'reject');
throw new Error('reject1')
}).then(null.res= > {
console.log(res, 'reject2');
})
Copy the code
Reject (reject) {reject (reject); reject (reject); reject (reject)
const createPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('promise')},1000)
})
createPromise.then(res= > {
1 / / results
console.log(res, 'resolved');
window.someNonexistentFunction()
}, res= > {
console.log(res, 'reject');
}).then(null.res= > {
console.log(res, 'reject');
})
Copy the code
Case 3 can use a try catch in the reject callback because it is synchronous code, but does not directly catch promise.reject ().
const createPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('promise')},1000)
})
createPromise.then(res= > {
console.log(res, 'resolved');
}, res= > {
console.log(res, 'reject');
try {
window.test()
} catch(e) {
console.log(e, 'e');
}
}).then(null.res= > {
console.log(res, 'reject2');
})
Copy the code
4.4.2 promise.prototype. Catch (
Features:
Because of the "bubbling" nature of errors in Promise objects, they are passed backwards until they are caught. That is, an error is always caught by the next catch statement. The catch() method still returns a Promise object, so you can call the then() method later.Copy the code
Keep in mind that the promise.prototype.catch () method is used to add a rejection handler to the contract, which accepts only one parameter: the onRejected handler. In fact, this method is a syntactic sugar; calling it is equivalent to calling promise.prototype. then(null, onRejected)
The following two are equal:
let p = Promise.reject();
let onRejected = function(e) {
setTimeout(console.log, 0.'rejected');
};
// The two ways to add rejection handlers are the same:
p.then(null, onRejected); // rejected
p.catch(onRejected); // rejected
Copy the code
Case 1: Throwing error of bubbling nature
const createPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('promise')},1000)
})
createPromise.then((res) = > {
console.log(res, 'resolved')
}).then(() = > {
console.log(res, 'resolved')
}).then(() = > {
console.log(res, 'resolved')
}).then(() = > {
console.log(res, 'resolved')},res= > {
console.log(res, 'reject')})Copy the code
Case 2 catch is also the same as the Reject callback, which has the bubbling nature of catching errors. Once an error is reported, no matter how many new promises are created, it is still caught later
const createPromise = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('promise')},1000)
})
createPromise.then((res) = > {
console.log(res, 'resolved')
}).then(() = > {
console.log(res, 'resolved')
}).then(() = > {
console.log(res, 'resolved')
}).catch((res) = > {
console.log(res, 'catch reject');
})
Copy the code
In case 3, an error is caught and a new promise is made. The cATH callback does not report an error, and the next then callback is left resolved
const createPromise = new Promise((resolve, reject) = > {
reject('promise');
})
createPromise.then(res= > {
console.log('resolved1', res)
})
.then(res= > {
console.log('resolved2', res)
})
.catch(res= > {
console.log('catche reject', res)
})
.then(res= > {
console.log('resolved3', res)
})
Copy the code
4.4.3 Async/await combined with try… Catch the use of
What is async function?
1. Async functions can be viewed as multiple asynchronous operations wrapped as a Promise object, and await commands are syntactic candy of internal THEN commands. 2. Async returns a Promise object, which can be added using the then method. When a function executes, it returns as soon as it encounters await, waits for the asynchronous operation to complete, and then executes the following statement in the function body.Copy the code
What is the await command? What are the characteristics
1. Await can only be used in async function. 2. Await expression suspends execution of the current async function until the Promise processing completes. If the Promise is fulfilled normally, the resolve function parameter of its callback will be the value of the await expression and the async function will continue to be executed. 3. If a Promise handles an exception (Rejected), the await expression will throw the exception reason of the Promise. 4. Await if a promise is returned with a reject state, the async function will be interrupted if it is not caught and thrown. 5. Also, if the value of the expression after the await operator is not a Promise, the value itself is returned. 6. In async await functions, try/catch blocks are usually used to catch errors.Copy the code
In plain English, the return value after await is the result of the resolve and reject callbacks
‘await result’ console.log(res, ‘await result’); ‘await result’ = ‘reject()’; If a request fails, it will interrupt all of our code execution, which is obviously not the desired result. So how can we make the call interface fail and still continue to operate?
const createPromise = new Promise((resove, reject) = > {
setTimeout(() = > {
console.log('I came in anyway.')
reject('promise')},1000)})async function awaitTest() {
const res = await createPromise
console.log(res, 'await result');
}
awaitTest()
Copy the code
Case 2 performs a try catch on the result
const createPromise = new Promise((resove, reject) = > {
setTimeout(() = > {
console.log('I came in anyway.')
reject('promise')},1000)})async function awaitTest() {
try {
const res = await createPromise
} catch(e) {
console.log(e, 'await call error! ');
}
console.log('Do you mind if I execute it? ');
}
awaitTest()
Copy the code
Have you ever thought about a question? ‘await’ returns a ‘reject’ callback, or ‘resolve’ callback. How do I know that an error is returned by a try catch? Why should I report an error when I return reject? Here’s another good thing I found:
When the promise function calls reject() to reject a contract, there are actually three equivalents
throw new Error('test');
Copy the code
try {
throw new Error('test');
} catch(e) {
reject(e);
}
Copy the code
Is equivalent to
reject(new Error('test'));
Copy the code
A try catch must catch a throw new Error
In what case is reject(new Error()) equivalent to throw new Error(‘ I’m an Error, no reject()’)
const createPromise = new Promise((resove, reject) = > { reject(new Error()) })
createPromise.then((res) = > {
console.log(res, 'resolved'); }
).catch(res= > { console.log(res, 'catch'); })
Copy the code
const createPromise = new Promise((resove, reject) = > { reject(new Error()) })
createPromise.then((res) = > {
throw new Error('I'm a mistake, no reject()')}
).catch(res= > { console.log(res, 'catch'); })
Copy the code
In both cases, an error can be caught with promise.catch (), which corresponds to es6 equivalence, but only if there is no asynchracy in the new Promise.
So why throw new Error(‘ I’m an Error, no reject()’) is equal to reject(new Error())?
Source code parsing: segmentfault.com/a/119000001…
A new Error(‘ I’m a mistake, no reject()’) is thrown, which is a reject() Error. So we’re calling the reject settle, and we said that a catch in a try or catch can’t catch a setTimeOut error
const createPromise = new Promise((resove, reject) = >
{ setTimeout(() = > { reject() }, 1000) })
createPromise.then((res) = > { console.log(res, 'resolved'); })
.catch(res= > { console.log(res, 'catch'); })
Copy the code
const createPromise = new Promise((resove, reject) = > { setTimeout(() = >
{ throw new Error('I'm a mistake, no reject()')},1000) })
createPromise.then((res) = > { console.log(res, 'resolved'); })
.catch(res= > { console.log(res, 'catch'); })
Copy the code
Throw new Error(‘ I’m a mistake, no reject()’), but not promise.catch()
As mentioned above, the first try catch in the source code cannot catch a setTimeOut, which contains the _state four states
_state === 0 // pending
state === 1 // forget, implement the resolve function, and _value instanceof Promise === true
_state === 2 // Reject executes the reject function
_state === 3 // forget, implement the resolve function, and _value instanceof Promise === false
Copy the code
If resolve or reject is not called. Always a penging state with _state === 0. When there is no setTimeOut, a try catch throws new Error(), which automatically rejects (). If there is a setTimeOut, the first try catch does not apply to the setTimeOut inside, so _state Is always equal to 0, and the source code does something for new Promise:
If there is a setTimeOut, a pending state awaits a reject() or resolve() call. If there is no pending state, it cannot be reached by promise.catch()
The most important thing to understand here is that you can’t catch an asynchronous try catch Catch () is not the same as promise.catch(). If promise.catch() is not the same as promise.catch(), you should check the source code for promise.catch(). OnRejected)) how is implemented internally
Source code must follow the JS event polling mechanism!
Case 4: This is a big pity. The result can not be obtained with “await”, let alone can be captured with “try catch”. “await” means the result will be returned by the “depressing” state
const createPromise = new Promise((resove, reject) = > {
setTimeout(() = > {
throw new Error('I'm a mistake, but I don't want to settle, no reject()')},1000)})async function awaitTest() {
try {
console.log(Test '1')
const res = await createPromise // The internal was not settled at the time of the call, so the result could not be returned, and the assignment to res would not be completed
console.log(res, 'test 2')}catch(e) {
console.log(e, 'await call error! ');
}
console.log('Do you mind if I execute it? ');
}
awaitTest()
Copy the code
Case 5 Try catch faces the problem of multiple await capture
const createPromise1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject(Failed to '1')},1000)})const createPromise2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('2' failure)},1000)})const createPromise3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('3')},1000)})async function awaitTest() {
try {
await createPromise1
console.log('Do not execute');
await createPromise2
await createPromise3
} catch(e) {
console.log(e, 'await call error! ');
}
console.log('1. Can I do that? ');
}
awaitTest()
console.log('2 'can I do that? ');
Copy the code
The result is that several await errors are reported, and she will catch only the first one. After the catch, she will continue to run
But we still recommend multiple AWIAt items. If there is no correlation, we can use promise.all for concurrency
const createPromise1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject(Failed to '1')},1000)})const createPromise2 = new Promise((resolve, reject) = > {
setTimeout(() = > {
reject('2' failure)},1000)})const createPromise3 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('3')},1000)})async function awaitTest() {
const list = await Promise.all([createPromise1.catch((e) = > e),
createPromise2.catch((e) = > e), createPromise3.catch((e) = > e)])
console.log(list, 'list');
console.log('1. Can I do that? ');
}
awaitTest()
console.log('2 'can I do that? ');
Copy the code
4.5 Try catch failed to catch promise.resolve()
As mentioned above, if the main thread is executed before, during and after the try catch, then only the middle can catch an error. In fact, the example in 4.3 is already obvious
Let’s start with CHAPTER 11 of JS Advanced programming
4.5.1 Try catch throw new Error this is ok
try {
throw new Error('foo');
} catch(e) {
console.log(e, 'catch');
}
Copy the code
4.5.2 try catch 捕获不到 Promise.reject()
try {
Promise.reject()
} catch(e) {
console.log(e, 'catch');
}
Copy the code
The first thing you need to know is that these two contract instances are actually the same
let p1 = new Promise((resolve, reject) = > reject());
let p2 = Promise.reject();
Copy the code
Because P1, P2 is asynchronous, and try catch is synchronous code, and synchronous code executes first, asynchronously queues up in the task queue, waits for synchronization to complete, and then you can try in the callback of then The number of returns from catch or await, which merely captures the returned result, and does not capture the asynchronous code of the Promise
Resolve () : if it is accepted then, I can try and catch the result
When to use try catch and how to throw wrong
5.1 throw new Error ()
One mechanism that corresponds to a try/catch statement is the throw operator, which is used to throw a custom error at any time. The throw operator must have a value of any type. When the throw operator is used, the code stops execution immediately, unless the try/catch statement catches the value thrown
try {
window.someNonexistentFunction()
} catch(e) {
throw new Error('Error reported')
console.log('I'm going to execute.')}Copy the code
try {
window.someNonexistentFunction()
} catch(e) {
try {
throw new Error('Error reported')}catch(e) {
console.log('I'm going to execute.')}}Copy the code
5.2 Each function should be carefully evaluated and the circumstances that might cause them to fail. A good error-handling protocol ensures that only the errors you throw will happen.
For example, in utils, if the parameter passed is not specified, you can use if to determine the type, and then throw the error
As for the difference between throwing and catching errors, think of it this way: you should only catch errors when you know exactly what to do next. The purpose of catching errors is to prevent the browser from responding in its default way; The purpose of throwing an error is to provide information about why the error occurred
5.3 By inheriting custom error types, and prompts
class CustomError extends Error {
constructor(message) {
super(message);
this.name = "CustomError";
this.message = message; }}throw new CustomError("My message");
Copy the code
What are the types of errors
1 Error
2 InternalError
3 EvalError
4 RangeError
5 ReferenceError
6 SyntaxError
7 TypeError
8 URIError
Copy the code
1.Error is the base type. Other Error types inherit this type. As a result, all Error types share the same attributes, and browsers rarely throw errors of the Error type, which is mainly used by developers to throw custom errors
- InternalError This error occurs within the JS engine, especially if it has too much data to process and the stack grows beyond its critical limit. Example scenarios usually have some elements that are too large
This error occurs within the JS engine, especially when it has too much data to process and the stack grows beyond its critical limit. Example scenarios typically have some elements that are too large, such as "too many switch cases" (too many case clauses); "Too many parentheses in regular expression"; "Array initializer too Large"; "Too much recursion."Copy the code
- An error of type EvalError is thrown when an exception occurs using the eval() function, or if eval() is called illegally
4.RangeError is thrown when a value is out of bounds
new Array(-20) HTML :52 Uncaught RangeError: Invalid array length
const num = 1
let res = num.toFixed(-1)
console.log(res); HTML :53 Uncaught RangeError: toFixed() digits argument must be between 0 and 100
Copy the code
5.ReferenceError occurs when the object cannot be found. (This is why the famous “Object Expected” browser was wrong.) This error is often caused by accessing variables that do not exist
Console. log(num) // Exception capture HTML :56 Uncaught ReferenceError: num is not definedCopy the code
6.TypeError is common in JavaScript, mostly when a variable is not of the expected type, or when a method is accessed that does not exist
let o = new 10; / / throw TypeError
console.log("name" in true); / / throw TypeError
Function.prototype.toString.call("name"); / / throw TypeError
Copy the code
7.URIError, which will only happen if encodeURI() or decodeURI() is used but a URI of the wrong format is passed in
Seven Misidentification
A very important part of error handling is first identifying where errors might occur in the code type conversion errors data type errors communication errors 1. Use ==== instead of the == 2. If judgment condition, avoid type conversion 3 as much as possible. Communication error, mainly URL parameter passing (main error is incorrect URL format or sending data format, no use before sending data to server,encodeURIComponent() encoding))Copy the code
Encapsulate URL parameters
function addQueryStringArg(url, name, value) {
if (url.indexOf("?") = = -1){
url += "?";
} else {
url += "&";
}
url += '${encodeURIComponent(name)=${encodeURIComponent(value)}';
return url;
}
const url = "http://www.somedomain.com";
const newUrl = addQueryStringArg(url, "redir"."http://www.someotherdomain.com?a=b&c=d");
console.log(newUrl);
Copy the code
Distinguish between major and non-major errors,
The difference between non-critical errors and critical errors is mainly reflected in the impact on users
Non-critical errors do not affect the user's primary task; affects only one part of the page; can be restored. Repeat operation may succeed. Critical error Application absolutely cannot continue to run; errors seriously affect the user's primary goal; can cause other errors to occur.Copy the code
for (let mod of mods){
mod.init(); // Possible critical error
}
Copy the code
You can use
for (let mod of mods){
try {
mod.init();
} catch (ex){
// Handle the error here}}Copy the code
Methods can be encapsulated to distinguish between critical errors and non-critical errors
function logError(sev, msg) {
let img = new Image(),
encodedSev = encodeURIComponent(sev),
encodedMsg = encodeURIComponent(msg);
img.src = 'log.php? sev=${encodedSev}&msg=${encodedMsg}';
}
Copy the code
The logError() function takes two arguments: severity and an error message. The severity can be numerical or a string, depending on the logging system used. The main reason for using Image objects to send requests here is flexibility
Ix Debugging Technology
All major browsers have a JavaScript console that can be used to query for JavaScript errors. In addition, all of these browsers support writing JavaScript messages directly to the console via the Console object
9.1 Debugger Keyword
Recommendation: www.cnblogs.com/xiaoqi2018/…
9.2 Printing Messages on the Page
When we read information, we sometimes print it in the template
9.3 Encapsulating console.log() as required
For example, if you want to print a lot of objects in your browser, but you have to open them step by step, you can override the global console.log (I’m not making type checks here).
Rewrite the front:
console.log({data: { name: 1.age: 18 }})
Copy the code
rewritten
const consoleog = window.console.log console.log = function() { const args = JSON.stringify(... arguments) consoleog(args) } console.log({data: { name: 1, age: 18 }})Copy the code
Ten Throwing errors
Throwing errors is a great way to debug your code. If the error message is specific enough, you can determine the cause by looking at the error. Good error messages contain exact information about the cause of the error, thus reducing the amount of additional debugging
function divide(num1, num2) {
if (typeofnum1 ! ="number" || typeofnum2 ! ="number") {throw new Error("divide(): Both arguments must be numbers.");
}
return num1 / num2;
}
Copy the code
Finally finished writing, bad place please give advice
Do the front end of the day, a good effort to precipitate it ~