如何在 JavaScript 中使用 then 和 catch 与 Promise 配合使用 finally?
Javascript 异步编程使用 Promise 对象,它不会阻塞当前流程的执行,而是通知编译器尚有一些未完成的任务,并在任务完成后向系统返回信号。主要有两种可能性:Promise 对象要么成功完成,要么通过返回异常停止。为了处理来自 Promise 对象的异常,使用 catch() 方法。在 try-catch 方法中,我们还可以使用另一个名为“finally”的块。无论之前做了什么,它都会执行。对于 Promise,我们也可以使用 finally() 函数来实现相同的功能。因此,在本文中,我们的最终目标是了解如何在 Promise 中使用 then() 和 catch() JavaScript 方法与 finally 配合使用。
基本语法如下:
语法
promise .then( // do something with the result result => { ...} ) .catch( // handle error error => { ... } ) .finally( // do something when it has been executed successfully // or raised an error. // this work can be memory cleaning or similar task () => { ... } )
无论 Promise 是 fulfilled 还是 rejected,finally() 方法始终都会执行。换句话说,当调用 finally() 方法时,Promise 就会被 settled。finally() 函数在 ES2018 中首次出现。可以在 finally() 方法中放置在 Promise fulfilled 时销毁资源的代码,无论其结果如何。如果不使用 finally() 方法,我们需要在 then() 和 catch() 方法中清除我们的资源。
不使用 Finally
promise .then( // do something with the result result => { ...} // do something to clear resources ) .catch( // handle error error => { ... } // do something to clear resources )
then() 和 catch() 块包含重复的代码。通过添加 finally() 块,可以轻松避免这种重复。try...catch...finally 语句中的“finally”块与 finally() 函数是相关的构造。对于同步编程中的资源清理,请使用“finally”块。而 finally() 方法则用于异步程序。
让我们来看一个示例,其中我们创建一个“Connection”类来创建数据库连接(假设)。有两种不同的方法:run() 方法用于执行查询,另一个名为 terminate() 的方法用于终止连接并清理资源。连接类定义如下:
连接类
class Connection { run( query ) { if (query != 'Add' && query != 'Modify' && query != 'Remove') { throw new Error( `Invalid query: ${query}`); } console.log(`Running given query: ${query}`); return this; } terminate() { console.log( 'Terminating already connected connection' ) } }
然后我们定义一个 connect() 方法,该方法将创建一个连接对象并返回一个 Promise 对象来处理连接。当它完成操作时,会返回一个新的连接对象,否则会引发错误。让我们看看函数定义以清楚地理解。
Connect 方法
class Connection { run( query ) { if (query != 'Add' && query != 'Modify' && query != 'Remove') { throw new Error( `Invalid query: ${query}`); } console.log(`Running given query: ${query}`); return this; } terminate() { console.log( 'Terminating already connected connection' ) } }
在最后处理场景时,使用 finally() 块。在下面的示例中:因为 success 标志设置为 true,所以 connect() 函数解析为一个新的 Connection 对象。第一个 then() 方法通过执行 Insert 查询来执行,它也返回一个 Connection 对象。连接通过 globalConnection 保存。第二个 then() 方法执行 Select 查询,它也会抛出一个错误。finally() 方法终止连接,而 catch() 方法显示错误消息。
finally 方法的使用
let globalConnection; connect() .then( (connection) => { globalConnection = connection; return globalConnection.run( 'Add' ); }) .then( (connection) => { globalConnection = connection; return globalConnection.run( 'Remove' ); }) .then((connection) => { globalConnection = connection; return connection.run( 'Union' ); }) .catch( console.log ) .finally( () => { if ( globalConnection ) { globalConnection.terminate(); } });
完整的代码和相应的输出如下:
源代码
class Connection { run( query ) { if (query != 'Add' && query != 'Modify' && query != 'Remove') { throw new Error( `Invalid query: ${query}`); } console.log(`Running given query: ${query}`); return this; } terminate() { console.log( 'Terminating already connected connection' ) } } const success = true; function connect() { return new Promise( (resolve, reject) => { if ( success ) resolve( new Connection() ); else reject( 'Connection cannot be created' ); }); } let globalConnection; connect() .then( (connection) => { globalConnection = connection; return globalConnection.run( 'Add' ); }) .then( (connection) => { globalConnection = connection; return globalConnection.run( 'Remove' ); }) .then((connection) => { globalConnection = connection; return connection.run( 'Union' ); }) .catch( console.log ) .finally( () => { if ( globalConnection ) { globalConnection.terminate(); } });
输出
Running given query: Add Running given query: Remove Error: Invalid query: Union at Connection.run (/home/cg/root/18775/main.js:4:16) at /home/cg/root/18775/main.js:36:25 Terminating already connected connection
使用 finally() 方法来 settled Promise,这会导致一个函数在 Promise fulfilled 或 rejected 时运行。无论 Promise 的结果如何,最好将清理资源的代码放在 finally() 方法中。
结论
在构建和分发系统到另一个平台或构建可用的平台时,异常处理是一项至关重要的任务。异常处理使用 try-catch 块。catch 块的目的是使用已建立的逻辑来处理异常。我们与它们一起使用的另一个块是我们称之为“finally”的块,无论是否发生异常,它都会执行。但只有同步系统应该使用此过程。在异步编程中,由于延迟响应,错误可能会稍后出现。为了管理异常,我们可以使用 then() 方法,它类似于 try 块。但是,在这种情况下,我们使用 finally() 函数来获得与“finally”块相同的结果。无论 Promise 是成功执行还是出现错误,此函数通常用于执行清理操作。