Javascript 如何使用finally在promise对象上使用then和catch
Javascript的异步编程使用promise对象,它不会阻塞当前流的执行,但会告诉编译器有一些尚未完成的事情,并在完成时向系统返回一个信号。主要有两种可能性,promise对象要么成功完成,要么通过返回异常而停止。为了处理来自promise对象的异常,我们使用catch()方法。在try-catch方法中,我们也可以使用另一个名为’finally’的代码块。无论之前做了什么,它都会被执行。对于promise对象,我们也可以使用finally()函数来实现相同的效果。因此,在本文中,我们的最终目标是了解如何使用finally在promise对象上使用then()和catch()方法。
基本语法如下所示-
语法
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
() => { ... }
)
无论承诺接受还是拒绝,finally()方法总是会执行。换句话说,当调用finally()过程时,承诺被解决。在ES2018中,finally()函数首次亮相。无论承诺的结果如何,都可以将销毁资源的代码放在finally()方法中。如果不使用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()方法来处理最后的情况。在下面的示例中:因为成功标志被设置为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”代码块相同的结果。每当承诺已成功执行或出现错误时,通常会使用此函数来执行清理操作。