作者: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.reject
和Promise.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
除了 then
和 catch
, 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 都失败/回绝),就返回一个失败的 promise
和AggregateError
类型的实例,它是 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都曾经fulfilled
或rejected
后的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
。这意味着咱们能够在函数调用之后进行then
、catch
和finally
操作
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有两种根本办法:on
和emit
。
思考以下简略的 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!");});
这里咱们来听两个事件:listening
和connection
。除了这些事件之外,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简直都偏差 Promise
。 then/catch/finally
或try/catch
的模式对于async/await
的异样解决变得更加容易。
代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。
原文:https://www.valentinog.com/bl...
交换
文章每周继续更新,能够微信搜寻 【大迁世界 】 第一工夫浏览,回复 【福利】 有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,欢送Star。