User feedback opened the page white screen, how to locate the error cause? How can you be sure that a daily release has not introduced a bug? How important it is to catch bugs in your code and report them.

Since catching errors and reporting them is an integral part of daily development, how do you catch them? Everything try… catch


try{

throw new Error()}catch(e) {

// handle error

}
Copy the code

It seems so simple to catch errors, but the following scenario does not catch them


try {

setTimeout((a)= > {

throw new Error('error')})}catch (e) {

// handle error

}
Copy the code

You will notice that the error in the above example does not catch properly. You can also wrap asynchronous functions with a try… Catch **

In the browser, **window.onerror** catches your error


window.onerror = function (msg, url, row, col, error) {

console.log('error');

console.log({

msg, url, row, col, error

})

};
Copy the code

You can create a simple **img** and use ** SRC ** to specify the address of the report. You can merge the report to avoid sending too many requests. Data can be periodically reported to the server.

But when you read the error message, you will find some of these errors **Script error**

The same origin policy of the browser raises Script errors for different domain names. How to solve this problem? Especially now basically JS resources will be placed on the CDN.

The solution

1: All resources are stored under the same domain name. However, the problem is that the advantages of CDN cannot be taken advantage of.

2: add cross-domain resource support, add cross-domain request support for primary domain on CDN, add **crossorigin** attribute in script tag

In using promises, if you don’t have a catch, you can catch an error this way

window.addEventListener("unhandledrejection".function(err, promise) { 
    // handle error here, for example log   
});
Copy the code

How do I catch errors in NodeJs

Error catching in NodeJs is important because improper handling can lead to an avalanche of unusable services. Of course, not only do you know how to catch errors, but you also know how to avoid certain errors.

  • When you’re writing a function, you’ve probably thought that when errors occur while the function is executing, should I throw it, use callback or Event Emitter, or some other method to distribute errors?

  • Should I check if the parameter is of the correct type, null

  • What do you do if the parameters don’t match? Throw an error or distribute it through, say, a callback?

  • What if you saved enough errors to duplicate the error scene?

  • What about catching some exception errors? try… Catch or domain

Operation error VS coding error

1. The operation is incorrect

Errors often occur at runtime, not because of a code bug, but because your system is running out of memory, file handles are running out, there is no network, etc

2. The code is incorrect

Coding errors are easier to understand, such as undefined being called as a function, or returning an incorrect data type, or a memory leak, etc

Handling operation error

  • You can log the mistakes and do nothing about it

  • You can also retry, for example, because the database failed to connect, but retry times are limited

  • You can also tell the front end of the error and try again later

  • Maybe you can do it directly, like create a path that doesn’t exist

Handling coding errors

Bad coding is difficult to handle because it is caused by coding errors. It’s actually a good idea to restart the process because

  • You’re not sure if a coding error will affect other requests, such as a database link failure due to a coding error, and other errors will make other requests unavailable

  • An I/O operation may be performed before an error is thrown, causing the I/O handle to be unable to close. This will occupy memory for a long time and may eventually cause the service to run out of memory.

  • In fact, the two points mentioned above do not solve the root of the problem. We should do a good test before going online, and do a good job of monitoring after going online. Once similar errors occur, we should monitor and alarm, pay attention to and solve the problem

How to distribute errors

  • In synchronous functions, an error is thrown directly

  • For some asynchronous functions, errors can be thrown through callback

  • Async /await can be used directly with try.. Catch error

  • EventEmitter throws an error event

NodeJs operations

A NodeJs application, only from the code level is difficult to ensure stable operation, but also from the operation level to ensure.

Multiple processes to manage your application

Once a single nodeJS process is down, the entire service becomes unavailable, so I think we need multiple processes to ensure that the service is available, with one process only responsible for starting, shutting down, and restarting other processes. Ensure that a process can be restarted immediately after it dies.

Consider the multi-process design in TSW. The master is responsible for the management of the worker. The worker and the master maintain the heartbeat monitoring, and immediately restart it once it is lost.

domain
process.on('uncaughtException'.function(err) {
    console.error('Error caught in uncaughtException event:', err);
});
process.on('unhandleRejection'.function(err) {
  // TODO
})
Copy the code

When the exception is caught in NodeJS, it can be described as violent. But by the time you catch the exception, you’ve lost the context, which is essentially a request. If something goes wrong with a Web service, you still want to be able to return some bottom-line content to improve the user experience. For example, server rendering or isomorphism, even if it fails, can return static HTML and go down the degrade route, but the context has been lost. There’s nothing I can do.

function domainMiddleware(options) {
    return async function (ctx, next) {
        const request = ctx.request;
        const d = process.domain || domain.create();
        d.request = request;
        let errHandler = (err) = > {
            ctx.set('Content-Type'.'text/html; charset=UTF-8');
            ctx.body = options.staticHtml;
        };
        d.on('error', errHandler);
        d.add(ctx.request);
        d.add(ctx.response);
        try {
            await next();
        } catch(e) {
            errHandler(e)
        }
    }
Copy the code

The above is a simple KOA2 domain middleware, using the domain to monitor error events, each Request Request, Response object in error, will trigger error events, when the error occurs, can be based on the context, can go to the degraded scheme.

How to avoid memory leaks

Memory leaks are common, especially when the front end writes to the back end, when closures are used incorrectly, and when circular references are used.

  • Do not block the execution of Event loops, especially large loops or IO synchronization operations

    for ( var i = 0; i < 10000000; i++ ) {
        var user       = {};
        user.name  = 'outmem';
        user.pass  = '123456';
        user.email = 'outmem[@outmem](/user/outmem).com';
    }
    Copy the code

    The long loop above causes a memory leak because it is synchronous code that will be executed in the process, and V8 will not be able to reclaim the memory generated by the loop at the end of the loop, which will cause the memory to grow. It is also possible that the long execution blocks node from going to the next Event loop, causing too many callbacks in the queue waiting to be processed, further increasing the memory usage. So what’s the solution?

    SetTimeout can be used to place the operation in the next loop to reduce the long loop and synchronize IO resistance to the process. Blocking the execution of the next loop also results in application performance degradation

  • A module’s private variables and methods are resident in memory

var leakArray = [];   
exports.leak = function () {  
  leakArray.push("leak" + Math.random());  
};
Copy the code

When requiring a module in node, a singleton will be formed in the end, which means that the function memory will grow as long as the function is called, and the closure will not be recycled. Secondly, leak method is a private method, and this method will always be in memory. Add that this method is called on every request, and memory will blow up after a while.

This scenario is actually quite common

// main.js
function Main() {
  this.greeting = 'hello world';
}
module.exports = Main;
Copy the code
var a = require('./main.js') ();var b = require('./main.js') (); a.greeting ='hello a';
console.log(a.greeting); // hello a
console.log(b.greeting); // hello a
Copy the code

Require is a singleton. When each request is executed on a server, the operation is a singleton. In this way, the variables or attributes generated by each execution will always be attached to this object and cannot be reclaimed, occupying a large amount of memory.

In fact, the above can be called in the following way, each time an instance is generated, and the collection is exhausted.

var a = new require('./main.js');
// TODO
Copy the code

Sometimes it is difficult to avoid problems that may cause memory leaks, so you can use the VM to call in a sandbox environment every time it is called, and recycle it when it is used up.

  • The last thing to do is to avoid circular references, which would also make it impossible to recycle