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

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

大家都说简历没我的项目写,我就帮大家找了一个我的项目,还附赠【搭建教程】。

应用 Promise 处理错误

为了演示 Promise 解决形式,咱们先回到一开始的那个事例:

function toUppercase(string) {  if (typeof string !== "string") {    throw TypeError("Wrong type given, expected a string");  }  return string.toUpperCase();}toUppercase(4);

绝对简略抛出异样,咱们能够应用 Promise.rejectPromise.resolve:

function toUppercase(string) {  if (typeof string !== "string") {    return Promise.reject(TypeError("Wrong type given, expected a string"));  }  const result = string.toUpperCase();  return Promise.resolve(result);}

因为应用了 Promise ,所以能够应用 then 来接管返回的内容,或者用 catch 来捕捉呈现的谬误。

toUppercase(99)  .then(result => result)  .catch(error => console.error(error.message));

下面的执行后果:

Wrong type given, expected a string

除了 thencatch , Promise 中还有 finally 办法,这相似于try/catch 中的 finally

toUppercase(99)  .then(result => result)  .catch(error => console.error(error.message))  .finally(() => console.log("Run baby, run"));

Promise, error, 和 throw

应用 Promise.reject 能够很不便的抛出谬误:

Promise.reject(TypeError("Wrong type given, expected a string"));

除了Promise.reject,咱们也能够通过抛出异样来退出 Promise。

思考以下示例:

Promise.resolve("A string").then(value => {  if (typeof value === "string") {    throw TypeError("Expected a number!");  }});

要进行异样流传,咱们照常应用catch

Promise.resolve("A string")  .then(value => {    if (typeof value === "string") {      throw TypeError("Expected a number!");    }  })  .catch(reason => console.log(reason.message));

这种模式在fetch中很常见:

fetch("https://example-dev/api/")  .then(response => {    if (!response.ok) {      throw Error(response.statusText);    }    return response.json();  })  .then(json => console.log(json));

这里能够应用catch拦挡异样。如果咱们失败了,或者决定不捕捉它,异样能够在堆栈中自在冒泡。

应用 Promise 来解决定时器中的异样

应用定时器或事件无奈捕捉从回调引发的异样。

function failAfterOneSecond() {  setTimeout(() => {    throw Error("Something went wrong!");  }, 1000);}// DOES NOT WORKtry {  failAfterOneSecond();} catch (error) {  console.error(error.message);}

解决方案就是应用 Promise:

function failAfterOneSecond() {  return new Promise((_, reject) => {    setTimeout(() => {      reject(Error("Something went wrong!"));    }, 1000);  });}

应用reject,咱们启动了一个 Promise 回绝,它携带一个谬误对象。

此时,咱们能够应用catch解决异样:

failAfterOneSecond().catch(reason => console.error(reason.message));

应用 Promise.all 来处理错误

Promise.all(iterable) 办法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“实现(resolved)”或参数中不蕴含 promise 时回调实现(resolve);

const promise1 = Promise.resolve("All good!");const promise2 = Promise.resolve("All good here too!");Promise.all([promise1, promise2]).then((results) => console.log(results));// [ 'All good!', 'All good here too!' ]

如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败的起因是第一个失败 promise 的后果。

const promise1 = Promise.resolve("All good!");const promise2 = Promise.reject(Error("No good, sorry!"));const promise3 = Promise.reject(Error("Bad day ..."));Promise.all([promise1, promise2, promise3])  .then(results => console.log(results))  .catch(error => console.error(error.message));// No good, sorry!

同样,无论Promise.all的后果如何运行函数,finally 都会被执行:

Promise.all([promise1, promise2, promise3])  .then(results => console.log(results))  .catch(error => console.error(error.message))  .finally(() => console.log("Always runs!"));

应用 Promise.any 来处理错误

Promise.any() (Firefox > 79, Chrome > 85) 接管一个 Promise 可迭代对象,只有其中的一个 promise 胜利,就返回那个曾经胜利的 promise 。如果可迭代对象中没有一个 promise 胜利(即所有的 promises 都失败/回绝),就返回一个失败的 promiseAggregateError类型的实例,它是 Error 的一个子类,用于把繁多的谬误汇合在一起。实质上,这个办法和Promise.all()是相同的。

const promise1 = Promise.reject(Error("No good, sorry!"));const promise2 = Promise.reject(Error("Bad day ..."));Promise.any([promise1, promise2])  .then(result => console.log(result))  .catch(error => console.error(error))  .finally(() => console.log("Always runs!"));

在这里,咱们应用catch处理错误,输入如下:

AggregateError: No Promise in Promise.any was resolvedAlways runs!

AggregateError对象具备与根本Error雷同的属性,外加errors属性:

//  .catch(error => console.error(error.errors))//

此属性是由reject产生的每个独自谬误的数组

[Error: "No good, sorry!, Error: "Bad day ..."]

应用 Promise.race 来处理错误

Promise.race(iterable) 办法返回一个 promise,一旦迭代器中的某个promise解决或回绝,返回的 promise就会解决或回绝。

const promise1 = Promise.resolve("The first!");const promise2 = Promise.resolve("The second!");Promise.race([promise1, promise2]).then(result => console.log(result));// The first!

这里阐明,第一个 Promise 比第二个行执行完。那蕴含回绝的状况又是怎么样的?

const promise1 = Promise.resolve("The first!");const rejection = Promise.reject(Error("Ouch!"));const promise2 = Promise.resolve("The second!");Promise.race([promise1, rejection, promise2]).then(result =>  console.log(result));// The first!

如果把reject放在第一个又会怎么样?

const promise1 = Promise.resolve("The first!");const rejection = Promise.reject(Error("Ouch!"));const promise2 = Promise.resolve("The second!");Promise.race([rejection, promise1, promise2])  .then(result => console.log(result))  .catch(error => console.error(error.message));// Ouch!

应用 Promise.allSettled 来处理错误

Promise.allSettled()办法返回一个在所有给定的promise都曾经fulfilledrejected后的promise,并带有一个对象数组,每个对象示意对应的promise后果。

思考上面示例:

const promise1 = Promise.resolve("Good!");const promise2 = Promise.reject(Error("No good, sorry!"));Promise.allSettled([promise1, promise2])  .then(results => console.log(results))  .catch(error => console.error(error))  .finally(() => console.log("Always runs!"));

咱们传递给Promise.allSettled一个由两个Promise组成的数组:一个已解决,另一个被回绝。

这种状况 catch 不会被执行, finally 永远会执行。

[  { status: 'fulfilled', value: 'Good!' },  {    status: 'rejected',    reason: Error: No good, sorry!  }]

应用 async/await 来处理错误

为了简略起见,咱们应用后面的同步函数toUppercase,并通过在function关键字前搁置async来将其转换为异步函数

async function toUppercase(string) {  if (typeof string !== "string") {    throw TypeError("Wrong type given, expected a string");  }  return string.toUpperCase();}

只有在函数后面加上async,该函数就会返回一个Promise。这意味着咱们能够在函数调用之后进行thencatchfinally 操作

async function toUppercase(string) {  if (typeof string !== "string") {    throw TypeError("Wrong type given, expected a string");  }  return string.toUpperCase();}toUppercase("abc")  .then(result => console.log(result))  .catch(error => console.error(error.message))  .finally(() => console.log("Always runs!"));

当从 async 函数抛出异样时,咱们就能够应用 catch 来捕捉。

最重要的是,除了这种形式外,咱们能够还应用try/catch/finally,就像咱们应用同步函数所做的一样。

async function toUppercase(string) {  if (typeof string !== "string") {    throw TypeError("Wrong type given, expected a string");  }  return string.toUpperCase();}async function consumer() {  try {    await toUppercase(98);  } catch (error) {    console.error(error.message);  } finally {    console.log("Always runs!");  }}consumer(); 

输入:

Wrong type given, expected a stringAlways runs!

应用 async generators 来处理错误

JavaScript中的async generators是可能生成 Promises 而不是简略值的生成器函数。

async function* asyncGenerator() {  yield 33;  yield 99;  throw Error("Something went wrong!"); // Promise.reject}

基于 Promise,此处实用于错误处理的雷同规定。 在异步生成器中 throw 将会触发 Promise 的reject,咱们能够应用catch对其进行拦挡。

为了应用异步生成器的 Promise,咱们能够这样做:

  • then 办法
  • 异步遍历

从下面咱们晓得,在两次调用 yield之后,下一次会抛出一个异样:

const go = asyncGenerator();go.next().then(value => console.log(value));go.next().then(value => console.log(value));go.next().catch(reason => console.error(reason.message));

输入后果:

{ value: 33, done: false }{ value: 99, done: false }Something went wrong!

别一种是应用 异步遍历for await...of:

async function* asyncGenerator() {  yield 33;  yield 99;  throw Error("Something went wrong!"); // Promise.reject}async function consumer() {  for await (const value of asyncGenerator()) {    console.log(value);  }}consumer();

有了 async/await 咱们能够应用 try/catch 来捕捉异样:

async function* asyncGenerator() {  yield 33;  yield 99;  throw Error("Something went wrong!"); // Promise.reject}async function consumer() {  try {    for await (const value of asyncGenerator()) {      console.log(value);    }  } catch (error) {    console.error(error.message);  }}consumer();

输入后果:

3399Something went wrong!

从异步生成器函数返回的迭代器对象也具备throw()办法,十分相似于其同步正本。在此处的迭代器对象上调用throw()不会引发异样,然而会被Promise回绝

async function* asyncGenerator() {  yield 33;  yield 99;  yield 11;}const go = asyncGenerator();go.next().then(value => console.log(value));go.next().then(value => console.log(value));go.throw(Error("Let's reject!"));go.next().then(value => console.log(value)); // value is undefined

要从内部解决这种状况,咱们能够做:

go.throw(Error("Let's reject!")).catch(reason => console.error(reason.message));

Node 中的错误处理

Node 中的同步错误处理

Node.js 中的同步错误处理与到目前为止所看到的并没有太大差别。对于同步,应用 try/catch/finally 就能够很好的工作了。

Node.js 中的异步错误处理:回调模式

对于异步代码,Node.js 次要应用这两种形式:

  • 回调模式
  • event emitters

在回调模式中,异步 Node.js API 承受一个函数,该函数通过事件循环解决,并在调用堆栈为空时立刻执行。

思考以下代码:

const { readFile } = require("fs");function readDataset(path) {  readFile(path, { encoding: "utf8" }, function(error, data) {    if (error) console.error(error);    // do stuff with the data  });}

咱们能够看到,这里处理错误的形式是应用了回调:

//function(error, data) {    if (error) console.error(error);    // do stuff with the data  }//

如果应用fs.readFile读取给定门路而引起任何谬误,咱们将取得一个谬误对象。

在这一点上,咱们能够:

  • 简略的把对象谬误打进去
  • 抛出谬误
  • 把谬误传到另一个回调

咱们能够抛出一个异样

const { readFile } = require("fs");function readDataset(path) {  readFile(path, { encoding: "utf8" }, function(error, data) {    if (error) throw Error(error.message);    // do stuff with the data  });}

然而,与 DOM 中的事件和定时器一样,此异样将使程序解体。 通过try/catch捕捉它是不起作用的:

const { readFile } = require("fs");function readDataset(path) {  readFile(path, { encoding: "utf8" }, function(error, data) {    if (error) throw Error(error.message);    // do stuff with the data  });}try {  readDataset("not-here.txt");} catch (error) {  console.error(error.message);}

如果咱们不想使程序解体,则将谬误传递给另一个回调是首选办法:

const { readFile } = require("fs");function readDataset(path) {  readFile(path, { encoding: "utf8" }, function(error, data) {    if (error) return errorHandler(error);    // do stuff with the data  });}

这里的errorHandler顾名思义,是一个用于错误处理的简略函数:

function errorHandler(error) {  console.error(error.message);  // do something with the error:  // - write to a log.  // - send to an external logger.}

Node.js 中的异步错误处理:event emitters

在 Node.js 中所做的大部分工作都是基于事件的。 大多数状况下,emitter object 和一些观察者进行交互以侦听音讯。

Node.js中的任何事件驱动模块(例如net)都扩大了一个名为EventEmitter的根类。

Node.js中的EventEmitter有两种根本办法:onemit

思考以下简略的 HTTP 服务器:

const net = require("net");const server = net.createServer().listen(8081, "127.0.0.1");server.on("listening", function () {  console.log("Server listening!");});server.on("connection", function (socket) {  console.log("Client connected!");  socket.end("Hello client!");});

这里咱们来听两个事件:listeningconnection。除了这些事件之外,event emitters 还公开一个 error 事件,以防产生谬误。

如果在端口80上运行这段代码,而不是在后面的示例上侦听,将会失去一个异样:

const net = require("net");const server = net.createServer().listen(80, "127.0.0.1");server.on("listening", function () {  console.log("Server listening!");});server.on("connection", function (socket) {  console.log("Client connected!");  socket.end("Hello client!");});

输入:

events.js:291      throw er; // Unhandled 'error' event      ^Error: listen EACCES: permission denied 127.0.0.1:80Emitted 'error' event on Server instance at: ...

要捕捉它,咱们能够注册一个error事件处理程序:

server.on("error", function(error) {  console.error(error.message);});

输入后果:

listen EACCES: permission denied 127.0.0.1:80

总结

在这个指南中,咱们介绍了JavaScript的各种错误处理,从简略的同步代码到高级的异步。在JavaScript程序中,能够通过多种形式来捕捉异样。

同步代码中的异样是最容易捕捉的。相同,异步中的异样须要一些技巧来解决。

浏览器中的新JavaScript API简直都偏差 Promisethen/catch/finallytry/catch的模式对于async/await的异样解决变得更加容易。


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

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

交换

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