{"id":22337760,"url":"https://github.com/boweihan/callbackpreserver","last_synced_at":"2026-05-10T19:03:47.650Z","repository":{"id":98803532,"uuid":"168850047","full_name":"boweihan/callbackpreserver","owner":"boweihan","description":"Utility class that preserves JavaScript callbacks to support multiple invocation - built on top of ES6 generators with TypeScript.","archived":false,"fork":false,"pushed_at":"2019-02-09T20:23:56.000Z","size":629,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-26T14:01:10.608Z","etag":null,"topics":["callbacks","es6","generators","javascript","js","microsoft-excel","microsoft-javascript-api","microsoft-js-api","npm-package","refactoring","refactoring-tools","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/callbackpreserver","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boweihan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-02T16:13:24.000Z","updated_at":"2021-03-25T16:53:24.000Z","dependencies_parsed_at":"2023-06-18T20:40:22.614Z","dependency_job_id":null,"html_url":"https://github.com/boweihan/callbackpreserver","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boweihan%2Fcallbackpreserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boweihan%2Fcallbackpreserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boweihan%2Fcallbackpreserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boweihan%2Fcallbackpreserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boweihan","download_url":"https://codeload.github.com/boweihan/callbackpreserver/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245616484,"owners_count":20644654,"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":["callbacks","es6","generators","javascript","js","microsoft-excel","microsoft-javascript-api","microsoft-js-api","npm-package","refactoring","refactoring-tools","typescript"],"created_at":"2024-12-04T06:11:16.364Z","updated_at":"2026-05-10T19:03:47.597Z","avatar_url":"https://github.com/boweihan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CallbackPreserver\n\n\u003cimg src=\"./preserver.png\" width=\"300px\"/\u003e\n\nA utility class for preserving JavaScript callback function context so that the same callback can be invoked multiple times.\n\n### Installation\n\n`npm install --save callbackpreserver`\n\n### Usage\n\n1. Instantiate CallbackPreserver.\n\n```\nimport CallbackPreserver from 'callbackpreserver';\nconst preserver = new CallbackPreserver();\n```\n\n2. Use CallbackPreserver -\u003e preserve() in place of a callback function to hold callback context for later.\n\n```\nconst methodThatAcceptsCallback = (callback) =\u003e {\n  const context = \"temporary context\";\n  callback(context);\n}\nmethodThatAcceptsCallback(preserver.preserve);\n```\n\n3. Use CallbackPreserver -\u003e run() to invoke the preserved original callback on demand.\n\n```\n// invoke preserved callback\npreserver.run((context) =\u003e {\n  console.log(context); // \"temporary context\"\n});\n\n// invoke preserved callback again - idempotence\npreserver.run((context) =\u003e {\n  console.log(context); // \"temporary context\"\n});\n```\n\n### Use-Cases\n\nCallbackPreserver provides a simple mechanism for code cleanliness. However, this pattern shines when used in conjuction with certain APIs that require batched context-aware callbacks. An example of this is Microsoft's `Excel.run` API used by O365 Addins to interact with Excel documents - https://docs.microsoft.com/en-us/office/dev/add-ins/excel/excel-add-ins-core-concepts.\n\nTypical usage of `Excel.run`:\n\n```\nExcel.run(function (context) {\n  // load the selected range\n  const selectedRange = context.workbook.getSelectedRange();\n  selectedRange.load('address');\n  context.sync()\n    .then(function () {\n      console.log('The selected range is: ' + selectedRange.address);\n  });\n\n  // load sheet names\n  var sheets = context.workbook.worksheets;\n  sheets.load(\"items/name\");\n  return context.sync()\n    .then(function () {\n      for (var i in sheets.items) {\n        console.log(sheets.items[i].name);\n      }\n    });\n})\n```\n\nIn the above example, the callback accepted by `Excel.run` is invoked with a proxy context object which is run asynchronously as a batch of operations. This makes it difficult to run your own JavaScript alongside Excel operations. This is where CallbackPreserver can come in.\n\n```\nconst preserver = new CallbackPreserver();\nExcel.run(preserver.preserve);\nawait preserver.run((context) =\u003e // perform Excel action)\n// run your own code\nawait preserver.run((context) =\u003e // perform Excel action)\n// run your own code\npreserver.close() // allow context to be garbage collected\n```\n\nWith CallbackPreserver the context can be reused across multiple invocations. In this example Excel operations that share a context can be pushed one at a time instead of in a batch.\n\n### API Interface\n\n```\ninterface ICallbackPreserver {\n  preserve: (...args: any[]) =\u003e void;\n  close: () =\u003e void;\n  run: (\n    callable: (...args: any[]) =\u003e Promise\u003cany\u003e,\n  ) =\u003e Promise\u003cany\u003e | Promise\u003cnever\u003e;\n}\n\n```\n\n### Notes\n\nCallbackPreserver is an experimental code cleanup mechanism that utilizes ES6 generators under the hood. Use at your own risk!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboweihan%2Fcallbackpreserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboweihan%2Fcallbackpreserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboweihan%2Fcallbackpreserver/lists"}