Скажем, у меня есть эта функция (psuedo-code):
function Foo() {
let varThatRequiresCleanup = //something
if(condition1) {
return Error1;
}
if(condition2) {
return Error2;
}
if(condition3) {
return Error3;
}
//etc.. more ifs and important code.
varThatRequiresCleanup.CleanUp();
return Success;
}
Исходя из мира C++ и C, я бы просто выполнил очистку в деструкторе или использовал goto
но JavaScript не имеет ни того, ни другого.
Как я буду обращаться к CleanUp()
когда возвращается Foo()
?
Является единственным методом вызова CleanUp()
в каждом, if
я вернусь?
В javascript вы можете определять и вызывать функции в функциях (т.е. В закрытии).
Таким образом, вы можете достичь того, что вам нужно, таким образом:
function Foo() {
let varThatRequiresCleanup = //something
// Define your "actual" Foo logic in an inner function
// where you can define your flow and return logic as
// needed.
function InnerFoo() {
// You can access variables in the Foo closure, like so
console.log(varThatRequiresCleanup);
if(condition1) {
return Error1;
}
if(condition2) {
return Error2;
}
if(condition3) {
return Error3;
}
//etc.. more ifs and important code.
return Success;
}
// Now call your inner function like so
var result = InnerFoo();
// Now you can cleanup resourced in scope of Foo as
// in this way, because this line will be hit
varThatRequiresCleanup.CleanUp();
// Return the result from InnerFoo()
return result;
}
Success
Одним из вариантов может быть использование функции для повторяющегося кода:
function Foo() {
let varThatRequiresCleanup = //something
function CleanUpAndReturn(returnValue) {
varThatRequiresCleanup.CleanUp();
return returnValue;
}
if (condition1) { return CleanUpAndReturn(Error1); }
if (condition2) { return CleanUpAndReturn(Error2); }
if (condition3) { return CleanUpAndReturn(Error3); }
//etc.. more ifs and important code.
return CleanUpAndReturn(Success);
}
Вы можете использовать блок try-finally:
function Foo() {
let varThatRequiresCleanup = //something
try {
if(condition1) {
return Error1;
}
if(condition2) {
return Error2;
}
if(condition3) {
return Error3;
}
//etc.. more ifs and important code.
return Success;
} finally {
varThatRequiresCleanup.CleanUp();
}
}
Вы можете сделать что-то, называемое патчем обезьяны.
Концепция взята отсюда.
function foo(){
if(condition1) {
return Error1;
}
if(condition2) {
return Error2;
}
if(condition3) {
return Error3;
}
}
var tempFoo = foo;
window.foo = function() {
tempFoo();
//do the cleanup here
CleanUp();
}
Вы можете использовать прокси, чтобы перехватывать вызовы к вашим методам.
Он работает, возвращая new Proxy
конструктору. Затем мы обрабатываем вызовы get
, и с этим мы можем сначала вызвать метод, а затем запустить очистку после этого. Это позволит нам только вызывать очистку один раз внутри прокси-сервера, а не внутри самого метода.
class MyClass {
constructor() {
this.varThatRequiresCleanup = null
// Create a reference to 'this' so the function below can use it
let $this = this
// A private function this will clean stuff up
// We can't use 'this' in this function because it references window
// We will use our reference '$this' instead
function cleanup() {
$this.varThatRequiresCleanup = null
console.log('cleaned up')
}
// Create a proxy that will handle the method calls
return new Proxy(this, {
get: (target, prop, receiver) => {
// Get the called property
let targetValue = Reflect.get(target, prop, receiver)
// Execute the called property
return (...args) => {
let r = targetValue.apply(this, args)
console.log('before varThatRequiresCleanup:', this.varThatRequiresCleanup)
cleanup()
console.log('after varThatRequiresCleanup:', this.varThatRequiresCleanup)
return r
}
}
})
}
Foo() {
this.varThatRequiresCleanup = 'foo'
return 'foo result'
}
Bar() {
this.varThatRequiresCleanup = 'bar'
return 'bar result'
}
}
let c = new MyClass()
console.log('Foo Return Value:', c.Foo())
console.log('-----------')
console.log('Bar Return Value:', c.Bar())