乐趣区

关于javascript:关于-JavaScript-错误处理的最完整指南上半部

作者:Valentino Gagliardi
译者:前端小智
起源:valentinog

点赞再看,微信搜寻 【大迁世界】 关注这个没有大厂背景,但有着一股向上踊跃心态人。本文 GitHub https://github.com/qq44924588… 上曾经收录,文章的已分类,也整顿了很多我的文档,和教程材料。

什么是编程中的谬误

咱们的开发过程中并不总是一帆风顺。特地是在某些状况下,咱们可能心愿进行程序或在产生不良状况时告诉用户。

例如:

  • 程序试图关上一个不存在的文件、
  • 网络连接断开
  • 用户输出了有效字符

在相似这些状况下,咱们能够本人写个自定义的谬误来治理,或者间接让引擎为咱们去定义这些谬误。有了谬误定义后,咱们能够用音讯告诉用户,或者进行执行程序的运行。

JavaScript 中的谬误是什么

JavaScript 中的谬误是一个对象。要在 JS 创立一个谬误,能够应用 Error 对象,如下所示:

const err = new Error('霍霍,如同哪里出问题了!')

也能够省略 new 关键字:

const err = Error('霍霍,如同哪里出问题了!')

创立,谬误对象有三个属性:

  • message: 带有谬误音讯的字符串
  • name:谬误的类型
  • stack:函数执行的堆栈跟踪

例如,咱们应用 TypeError 对象创立一个谬误,对应的 message 是创立的传入的字符号,name“TypeError” ????

const wrongType = TypeError("霍霍,如同哪里出问题了!")

wrongType.message // "霍霍,如同哪里出问题了!"
wrongType.name // "TypeError"

JavaScript 中的许多类型的谬误

JavaScript 中有很多类型的谬误 ????, 如:

  • Error
  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

记住,所有这些谬误类型都是理论的构造函数,意味着返回一个新的谬误对象。

在咱们的代码中,次要还是应用 ErrorTypeError这两种最常见的类型来创立本人的谬误对象 ????。

大多数时候,大多数谬误将间接来自 JavaScript 引擎,例如 InternalErrorSyntaxError

如果你从新赋值给 const 申明的变量时,就会引发 TypeError 谬误。

const name = "前端小智"
name = "王大冶"

// // TypeError: Assignment to constant variable.

SyntaxError 谬误个别是关键字打错了,如下所示:

va x = '33';
// SyntaxError: Unexpected identifier

或者,当在谬误的中央使关键字时,例如awaitasync 的应用:

function wrong(){await 99;}

wrong();

// SyntaxError: await is only valid in async function

另一个 TypeError 的例子是,在页面操作不存在的 DOM 元素。

Uncaught TypeError: button is null

除了这些内置谬误外,在浏览器中还有:

  • DOMException
  • DOMError,当初曾经废除,不再应用了。

DOMException是与 Web API 相干的一系列谬误。当咱们在浏览器中执行愚昧的操作时,它们会被抛出,例如:

document.body.appendChild(document.cloneNode(true));

后果:

Uncaught DOMException: Node.appendChild: May not add a Document as a child

什么是异样?

大多数开发人员认为谬误和异样是一回事。实际上,谬误对象只有在抛出时才会变成异样。

要在 JavaScript 中引发异样,咱们应用throw 关键字把谬误抛出去:

const wrongType = TypeError("霍霍,如同哪里出问题了!")

throw wrongType;

简写模式:

throw TypeError("霍霍,如同哪里出问题了!")

或者

throw new TypeError("霍霍,如同哪里出问题了!")

在函数体或者条件之外抛出异步的可能性不大,思考上面的例子:

function toUppercase(string) {if (typeof string !== "string") {throw TypeError("霍霍,如同哪里出问题了!");
  }

  return string.toUpperCase();}

这里咱们查看函数参数是否为字符串。如果不是,咱们抛出一个异样。从技术上讲,JavaScript 中能够抛出任何货色,而不仅仅是谬误对象

throw Symbol();
throw 33;
throw "Error!";
throw null;

然而,最好防止这些事件:始终抛出正确的谬误对象,而不是一些根本类型。

这样有助于在代码中,错误处理的一致性。其余成员能够冀望在谬误对象上拜访 error.messageerror.stack 来晓得谬误的源头。

当咱们抛出异样时会产生什么?

异样就像一个回升的电梯: 一旦你抛出一个,它就会在程序堆栈中冒泡,除非它在某个中央被捕捉。

思考以下代码:

function toUppercase(string) {if (typeof string !== "string") {throw TypeError("参数类型须要是 string 的");
  }

  return string.toUpperCase();}

toUppercase(4);

运行代码会在控制台看到:

Uncaught TypeError: Wrong type given, expected a string
    toUppercase http://localhost:5000/index.js:3
    <anonymous> http://localhost:5000/index.js:9

能够看到产生谬误的确切行。

这个报告是一个堆栈跟踪,它有助于跟踪代码中的问题。堆栈跟踪从下至上:

 toUppercase http://localhost:5000/index.js:3
    <anonymous> http://localhost:5000/index.js:9

除了在浏览器的控制台中看到此堆栈跟踪外,还能够通过谬误对象的 stack 属性进行查看。

如果异样未被捕捉,也就是说,程序员不采取任何措施来捕捉它,程序将解体。

何时何地捕捉代码中的异样取决于特定的用例。

例如,咱们可能想在堆栈中传递一个异样,以使程序齐全解体。这种状况产生在,让谬误进行程序比解决有效数据来得更平安。

接下来,咱们来看看 JavaScript 同步和异步中的谬误和异样解决。

同步中的错误处理

同步代码在大多数状况下都很简略,因而它的错误处理也很简略。

惯例函数的错误处理

同步代码的执行程序与写入程序雷同。咱们再看一下后面的例子:

function toUppercase(string) {if (typeof string !== "string") {throw TypeError("参数类型须要是 string 的");
  }

  return string.toUpperCase();}

toUppercase(4);

在这里,引擎调用并执行toUppercase。所有这些都是同步产生的。要捕捉同步函数引发的异样,咱们能够应用try/catch/finally

try {toUppercase(4);
} catch (error) {console.error(error.message);
} finally {}

try/catch/finally是一个同步构造,但它也能够捕捉异步呈现的异样。

应用 generator 函数来处理错误

JavaScript 中的 生成器函数 是一种非凡的函数。除了在其外部作用域和使用者之间提供双向通信通道之外,还能够随便 暂停 复原

要创立一个生成器函数,咱们在 function 关键字前面放一个*:

function* generate() {//}

在函数内能够应用 yield 返回值:

function* generate() {
  yield 33;
  yield 99;
}

生成器函数的返回值是一个 迭代器对象(iterator object)。要从生成器中提取值,咱们能够应用两种办法:

  • 应用 next() 办法
  • 通过 for...of 遍历

如下所示,要想在生成器中获取值,咱们能够这样做:

function* generate() {
  yield 33;
  yield 99;
}

const go = generate();

const firstStep = go.next().value; // 33
const secondStep = go.next().value; // 99

成器也能够采纳其余办法工作:它们能够接管调用者返回的值和异样。

除了 next() 之外,从生成器返回的迭代器对象还具备 throw() 办法。应用这种办法,咱们能够通过向生成器中注入一个异样来进行程序

function* generate() {
  yield 33;
  yield 99;
}

const go = generate();

const firstStep = go.next().value; // 33

go.throw(Error("我要完结你!"));

const secondStep = go.next().value; // 这里会抛出异样

要获取此谬误,能够在生成器函数中应用 try/catch/finally:

function* generate() {
  try {
    yield 33;
    yield 99;
  } catch (error) {console.error(error.message);
  }
}

上面这个事例是应用 for...of 来获取 生成器函数中的值:

function* generate() {
  yield 33;
  yield 99;
  
  throw Error("我要完结你!")
}

try {for (const value of generate()) {console.log(value)
  }
} catch (error) {console.log(error.message)
}

/* 输入:33
  99
  我要完结你!
*/

异步中的错误处理

JavaScript 实质上是同步的,是一种单线程语言。

诸如浏览器引擎之类的宿主环境应用许多 Web API,加强了 JS 以与内部零碎进行交互并解决与 I/O 绑定的操作。

浏览器中异步操作有:定时器相干的函数、事件和 Promise。

异步中的错误处理不同于同步的错误处理。咱们来看一些例子。

定时器的错误处理

思考上面的代码片段:

function failAfterOneSecond() {setTimeout(() => {throw Error("Something went wrong!");
  }, 1000);
}

这个函数大概在 1 秒后抛出异样,解决这个异样的正确办法是什么?

上面的办法不起作用:

function failAfterOneSecond() {setTimeout(() => {throw Error("Something went wrong!");
  }, 1000);
}

try {failAfterOneSecond();
} catch (error) {console.error(error.message);
}

咱们晓得 try/catch 是同步,而 setTimeout 是异步的。当执行到 setTimeout回调时,try/catch 早已跑完了,所以异样就无奈捕捉到。

它们在两务不同的轨道上:

Track A: --> try/catch
Track B: --> setTimeout --> callback --> throw

如果能让程序跑下去,把 try/catch 挪动到 setTimeout 外面。但这种做法意义不大,前面咱们会应用 Promise 来解决这类的问题。

事件中错误处理

DOM 的事件操作(监听和触发),都定义在 EventTarget 接口。Element节点、document节点和 window 对象,都部署了这个接口。此外,XMLHttpRequest、AudioNodeAudioContext等浏览器内置对象,也部署了这个接口。该接口就是三个办法,addEventListenerremoveEventListener 用于绑定和移除监听函数,dispatchEvent用于触发事件。

DOM 事件的错误处理机制遵循任何异步 Web API 的雷同计划。

思考上面示例:

const button = document.querySelector("button");

button.addEventListener("click", function() {throw Error("Can't touch this button!");
});

在这里,单击按钮后立刻引发异样。咱们如何抓住它?上面这种形式没啥作用,也不会阻止程序解体:

const button = document.querySelector("button");

try {button.addEventListener("click", function() {throw Error("Can't touch this button!");
  });
} catch (error) {console.error(error.message);
}

setTimeout 一样,addEventListener 也是异步执行的。

Track A: --> try/catch
Track B: --> addEventListener --> callback --> throw

如果能让程序跑下去,把 try/catch 挪动到 addEventListener 外面。但这种做法意义不大,前面咱们会应用 Promise 来解决这类的问题。

onerror 怎么样

HTML 元素具备许多事件处理程序,例如 onclickonmouseenteronchange 等,当然还有 onerror

img 标签或 script 标签遇到不存在的资源时,onerror事件处理程序都会触发。

思考上面示例:

...
<body>
  <img src="nowhere-to-be-found.png" alt="So empty!">
</body>
...

当文件不存在时,控制台就会报如下的谬误:

GET http://localhost:5000/nowhere-to-be-found.png
[HTTP/1.1 404 Not Found 3ms]

在 JS 中,咱们能够通过 onerror 来捕捉这个谬误:

const image = document.querySelector("img");

image.onerror = function(event) {console.log(event);
};

更好的形式:

const image = document.querySelector("img");

image.addEventListener("error", function(event) {console.log(event);
});

这种形式对于一些申请资源失落的状况很有用,但 onerrorthrowtry/cathc 无关。


代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

原文:https://www.valentinog.com/bl…

交换

文章每周继续更新,能够微信搜寻 【大迁世界】 第一工夫浏览,回复 【福利】 有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,欢送 Star。

退出移动版