共计 10326 个字符,预计需要花费 26 分钟才能阅读完成。
作者: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 WORK
try {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 resolved
Always 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 string
Always 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();
输入后果:
33
99
Something 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:80
Emitted '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。