DEV Community

Ivan Starkov
Ivan Starkov

Posted on

JS defer or how to free resources at the end of code block (fun way).

Interesting feature of the Go language is to delay the execution of a function until the current function returns - defer keyword.

It allows to declare resource cleanup near the place it created i.e.

file, err := os.Create(fileName)
if err != nil {
  return err
}
defer file.Close()
...
file.Close will be called at the end of function
...
Enter fullscreen mode Exit fullscreen mode

The similar feature in js is finally keyword. The issue with finally that you open resource in one place but need to close it far far away from opening position.

  • easy to make mistake
  • in case of dependent resources easy to break order etc.

In js we can have similar behavior like defer using generators, see example:

async function* createResource<T>(open: () => T, close: (a: T) => void) {
  let r: T | null = null;
  try {
    r = open();
    yield r;
  } finally {
    if (r != null) {
      close(r);
    }
  }
}

const open = () => {
  console.log('open');
  return 'somehandle';
};

const close = (handle: string) => {
  console.log(handle, 'closed');
};

for await (let x of createResource(open, close)) {
  console.log(1);
  await new Promise(x => setTimeout(x, 1000));
  console.log(2);
  // throw new Error();
}
Enter fullscreen mode Exit fullscreen mode

Output will be: 'open', 1, 2, 'somehandle closed'

Now our resource lifecycle is bounded to "for" block. We declared open, close in same place and it's somehow looks like defer.

PS: createResource should rethrow Error so its just small simple version to show the idea.

PPS: All above is just for fun to show generators power.

Top comments (0)