{"id":20529757,"url":"https://github.com/wofwca/safe-init-destroy","last_synced_at":"2026-04-21T04:32:54.696Z","repository":{"id":65018307,"uuid":"580503116","full_name":"WofWca/safe-init-destroy","owner":"WofWca","description":"The right way to write `destroy()` functions","archived":false,"fork":false,"pushed_at":"2023-04-25T14:32:49.000Z","size":15,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-02T01:40:02.151Z","etag":null,"topics":["async","constructor","deinit","destroy","destructor","init","library","observer-pattern","refactoring","utils"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/safe-init-destroy","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WofWca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-20T18:12:57.000Z","updated_at":"2023-04-30T08:09:23.000Z","dependencies_parsed_at":"2023-01-13T15:17:04.117Z","dependency_job_id":null,"html_url":"https://github.com/WofWca/safe-init-destroy","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WofWca%2Fsafe-init-destroy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WofWca%2Fsafe-init-destroy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WofWca%2Fsafe-init-destroy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WofWca%2Fsafe-init-destroy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WofWca","download_url":"https://codeload.github.com/WofWca/safe-init-destroy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242133818,"owners_count":20077143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","constructor","deinit","destroy","destructor","init","library","observer-pattern","refactoring","utils"],"created_at":"2024-11-15T23:33:59.714Z","updated_at":"2026-04-21T04:32:54.668Z","avatar_url":"https://github.com/WofWca.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# safe-init-destroy\n\nIf you have a function called `destroy` (or `deinit`) and it is longer than 3 lines, you may want to rewrite it using this approach.\n\n\u003e UDP: I just learned that this is an \"observer\" design pattern, so I guess the takeaway is \"the observer pattern is good in this case\".\n\n## Example\n\n\u003c!-- TODO maybe we should \"inline\" the `doSomething` functions. May be confusing. --\u003e\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eBefore\u003c/td\u003e\n      \u003ctd\u003eAfter\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003cthead\u003e\n    \u003ctbody\u003e\n      \u003ctr\u003e\n\u003ctd\u003e\n\n```js\n// ...\n\n\n\n\n\nfunction init() {\n  doSomething();\n\n  // ...\n  doSomethingElse();\n\n  // ...\n  if (cond) {\n    doSomeOtherThing();\n\n  }\n}\nfunction destroy() {\n  undoSomething();\n  undoSomethingElse();\n  if (didDoSomeOtherThing) {\n    undoSomeOtherThing();\n  }\n}\n// ...\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```diff js\n// ...\n+const {\n+  onDestroy,\n+  destroy\n+} = createDestructionManager();\n \n function init() {\n   doSomething();\n+  onDestroy(() =\u003e undoSomething());\n   // ...\n   doSomethingElse();\n+  onDestroy(() =\u003e undoSomethingElse());\n   // ...\n   if (cond) {\n     doSomeOtherThing();\n+    onDestroy(() =\u003e undoSomeOtherThing());\n   }\n }\n-function destroy() {\n-  undoSomething();\n-  undoSomethingElse();\n-  if (didDoSomeOtherThing) {\n-    undoSomeOtherThing();\n-  }\n-}\n // ...\n```\n\n\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\nSuch code is much more maintainable because all the related things are grouped together. If you change one piece of code, you won't forget to update its corresponding `destroy()` part (or vice versa), because it's immediately next to it (perhaps even inside the same nested code block).\n\n\u003c!-- TODO add async examples\n* Where `destroy` can be called before `init` has finished.\n* (maybe as a part of the previous point) Where in the init method we check if \n* Where we do some initialization outside of the `init` method, dynamically, (say, inside a different method) i.e. we don't know if that thing is going to be initialized. --\u003e\n\n## Feedback wanted\n\nI would like to hear feedback on this approach. I don't know why I havent's seen it implemented in the wild, yet I _have_ seen bloated `destroy` methods that look like they can break from a breath of wind (no offence). If you have seen similar code (even in different languages), or code that solves the same problem, or code that manages to avoid this problem, please let me know.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwofwca%2Fsafe-init-destroy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwofwca%2Fsafe-init-destroy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwofwca%2Fsafe-init-destroy/lists"}