{"id":17922583,"url":"https://github.com/rreverser/when-traverse","last_synced_at":"2025-06-18T12:38:25.500Z","repository":{"id":16141631,"uuid":"18887128","full_name":"RReverser/when-traverse","owner":"RReverser","description":"Asynchronously traverse tree of mixed promises and values","archived":false,"fork":false,"pushed_at":"2014-07-07T19:04:29.000Z","size":317,"stargazers_count":19,"open_issues_count":2,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-12-30T20:33:39.643Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/RReverser.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}},"created_at":"2014-04-17T17:27:17.000Z","updated_at":"2022-04-12T03:04:09.000Z","dependencies_parsed_at":"2022-09-08T06:50:40.209Z","dependency_job_id":null,"html_url":"https://github.com/RReverser/when-traverse","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/RReverser%2Fwhen-traverse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fwhen-traverse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fwhen-traverse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fwhen-traverse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RReverser","download_url":"https://codeload.github.com/RReverser/when-traverse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233704844,"owners_count":18717028,"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":[],"created_at":"2024-10-28T20:39:51.672Z","updated_at":"2025-01-13T07:18:51.641Z","avatar_url":"https://github.com/RReverser.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# when-traverse [![Build Status](https://travis-ci.org/RReverser/when-traverse.svg?branch=master)](https://travis-ci.org/RReverser/when-traverse)\n\n\u003e Asynchronously traverse tree of mixed promises and values\n\n## Why\n\nConsider this function as `Promise.map` + `Promise.all` for trees.\n\nOften enough, we have tree structures, and when we want to transform them asynchronously, we have no other options but use sync variants of functions or write ugly hacks by collecting arrays of inner promises, handling them with `Promise.all`, collecting new promises (if there are), waiting for them with `Promise.all` again and do a lot of other silly stuff.\n\nThis function allows you to wait for tree of mixed promises and simple values, replace some nodes with asynchronous content, remove nodes depending on asynchronous conditions etc.\n\nIt handles each node as soon as it becomes available for processing, thus resulting in low overall latency.\n\n## Dependencies\n\nFunction assumes that DOM API compliant `Promise` exists in global namespace (true for latest versions of Chrome and Firefox).\n\nIf it's not, for AMD and Node.js [polyfill](https://github.com/jakearchibald/es6-promise) will be loaded and used.\n\n## Install\n\nUse with AMD, Node.js or simple `\u003cscript src\u003e`.\n\n## Usage\n\n### Let's assume you have following asynchronous tree:\n\n```js\n// delayed promise helper (for example only)\nfunction delay(timeout, value) {\n  return new Promise(function (resolve) {\n    setTimeout(function () {\n      resolve(value);\n    }, timeout);\n  });\n}\n\n// sample tree with nested simple and promised nodes\nvar tree = {\n  a: 1,\n  b: delay(1000, {\n    'b1': delay(2000, 2),\n    'b2': delay(3000, 3)\n  }),\n  c: delay(4000, 4),\n  d: {\n    shouldNotGoHere: delay(5000, 5)\n  }\n};\n```\n\n### Then you can process it as follows:\n\n```javascript\nwhenTraverse(tree, {\n  enter: function enter(node, key, parentNode) {\n    // is called when node object itself is resolved but didn't enter subtree yet\n  },\n  leave: function leave(node, key, parentNode) {\n    // is called when node with all the children are resolved and subtree is processed\n  }\n}).then(function (tree) {\n  // got resolved tree here\n});\n```\n\nor\n\n```javascript\n// custom visit() function, you can process node and call this.into(node)\nwhenTraverse(tree, function visit(node, key, parentNode) {\n  // process each node here\n  return this.into(node); // and recursively visit children if needed\n}).then(function (tree) {\n  // got resolved tree here\n});\n```\n\nor\n\n```javascript\n// no changes, only waiting for all the promises in tree\nwhenTraverse(tree).then(function (tree) {\n  // got resolved tree here\n});\n```\n\n### From both `enter` and `leave` you can return either:\n\n1. nothing (so this node object will be left intouched);\n2. new node to replace old one with;\n3. `whenTraverse.SKIP` to skip further processing of this node and children (useful in `enter` when you don't want to wait for children transformations nor get this node in `leave`);\n4. `whenTraverse.REMOVE` to remove this node in parent;\n5. `Promise` of anything listed above.\n\n---\n\nCheck out [test.js](https://github.com/RReverser/when-traverse/blob/master/test.js) for more code.\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT) © Ingvar Stepanyan\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frreverser%2Fwhen-traverse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frreverser%2Fwhen-traverse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frreverser%2Fwhen-traverse/lists"}