如何在 Javascript 中将 finally 与 then 和 catch 结合使用?
Javascript 异步编程使用 promise 对象,该对象不会阻止当前流程的执行,但会通知编译器有些事情尚未完成,并且每当完成时都会向系统返回信号。主要有两种可能性。promise 对象将成功完成,或者它将通过返回异常而停止。要处理来自 promise 对象的异常,请使用 catch() 方法。在 try-catch 方法中,我们还可以使用另一个名为"finally"的块。无论之前执行了什么,它都会执行。对于承诺,我们也可以使用 finally() 函数来执行相同操作。因此,在本文中,我们的最终目标是了解如何将 finally 与 then() 和 catch() javascript 方法结合使用。
基本语法如下所示 −
语法
promise .then( // 对结果进行一些处理 result => { ...} ) .catch( // 处理错误 error => { ... } ) .finally( // 成功执行后执行某些操作 // 或引发错误。 // 这项工作可以是内存清理或类似的任务 () => { ... } )
无论承诺是被接受还是被拒绝,finally() 方法始终都会执行。换句话说,当调用 finally() 过程时,承诺就已完成。在 ES2018 中,finally() 函数首次亮相。无论承诺的结果如何,在承诺履行时销毁资源的代码都可以放在 finally() 方法中。如果不使用 finally() 方法,我们需要在 then() 和 catch() 方法中清除资源。
没有 Finally
promise .then( // 对结果进行处理 result => { ...} // 进行处理以清除资源 ) .catch( // 处理错误 error => { ... } // 做一些事情来清除资源 )
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() 方法,它将创建一个连接对象并返回一个承诺对象来处理该连接。当它完成其操作时,将返回一个新的连接对象,否则将引发错误。让我们看一下函数定义以便更清楚地理解。
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() 块来处理该场景。在下面的示例中:由于成功标志设置为 true,因此 connect() 函数解析为一个新的 Connection 对象。Insert 查询通过第一个 then() 方法执行,该方法也返回一个 Connection 对象。连接通过 globalConnection 保存。Select 查询由第二个 then() 函数运行,该函数也会抛出错误。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() 方法解决承诺,该方法在承诺被履行或拒绝时运行函数。无论承诺结果如何,最好将停用资源的代码放在 finally() 过程中。
结论
在构建系统并将其分发到另一个平台或构建可用平台时,异常处理是一项至关重要的任务。Try-catch 块用于异常处理。catch 块的目的是使用已建立的逻辑来处理异常。我们与它们一起使用的另一个块是我们称之为"finally"的块,无论是否发生异常,它都会运行。但同步系统只能使用此过程。由于响应延迟,错误可能会在异步编程中稍后出现。要管理异常,我们可以使用 then() 方法,它类似于 try 块。但是,在这种情况下,我们使用 finally() 函数来获得与"finally"块相同的结果。每当承诺成功执行或者出现错误时,此函数通常用于执行清理操作。