如何始终在功能结束时运行清理?

时间:2018-10-25 19:22:49

标签: javascript node.js

说我有这个功能(伪代码):

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的唯一方法吗?

5 个答案:

答案 0 :(得分:3)

一种替代方法是对重复代码使用函数:

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);
}

答案 1 :(得分:2)

在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;
}

答案 2 :(得分:1)

您可以做一个叫做猴子补丁的事情。

概念取自here

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();
}

答案 3 :(得分:1)

您可以使用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();
  }
}

答案 4 :(得分:0)

您可以使用代理来拦截对方法的调用。

通过将new Proxy返回给构造函数来工作。然后,我们处理get调用,然后我们可以首先调用该方法,然后再运行清理。这将使我们只需要在代理内调用一次清除,而不必在方法本身内调用。

  1. 创建返回新代理的实例
  2. 调用方法之一
    1. 代理将立即拦截并处理呼叫
    2. 代理将按原样运行该功能
    3. 然后代理将运行清理功能
    4. 然后代理将返回步骤2的结果

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())