{"id":17484736,"url":"https://github.com/creationix/do","last_synced_at":"2025-08-20T12:30:46.239Z","repository":{"id":63061668,"uuid":"520887","full_name":"creationix/do","owner":"creationix","description":"Do is a simple library for managing async actions in node.JS.","archived":false,"fork":false,"pushed_at":"2010-07-18T19:32:40.000Z","size":97,"stargazers_count":291,"open_issues_count":0,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-19T04:19:37.674Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/creationix.png","metadata":{"files":{"readme":"README.markdown","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":"2010-02-16T20:50:45.000Z","updated_at":"2024-09-23T10:14:05.000Z","dependencies_parsed_at":"2022-11-12T03:17:29.171Z","dependency_job_id":null,"html_url":"https://github.com/creationix/do","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fdo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fdo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fdo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fdo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creationix","download_url":"https://codeload.github.com/creationix/do/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230423559,"owners_count":18223435,"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-19T01:07:59.286Z","updated_at":"2024-12-19T11:11:06.955Z","avatar_url":"https://github.com/creationix.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `Do` it!\n\n`Do` is a library that adds higher level abstraction and continuables.  What I mean by a continuable is explained by the following:\n\n### Continuables\n\n    function divide(a, b) { return function (callback, errback) {\n      // Use nextTick to prove that we're working asynchronously\n      process.nextTick(function () {\n        if (b === 0) {\n          errback(new Error(\"Cannot divide by 0\"));\n        } else {\n          callback(a / b);\n        }\n      });\n    }}\n\n`Do` expects async functions to not require the callback in the initial invocation, but instead return a continuable which can then be called with the `callback` and `errback`.  This is done by manually currying the function. The \"continuable\" is the partially applied version of the function returned by the outer function.  The body of the function won't be executed until you finish the application by attaching a callback.\n\n    divide(100, 10)(function (result) {\n      puts(\"the result is \" + result);\n    }, function (error) {\n      throw error;\n    });\n\nThis style is extremely simple (doesn't require an external library like promises to use), and is fairly powerful.\n\n - The initial function can have variable arguments.\n - The continuable itself is portable until it's invoked by attaching callbacks.\n\n## Higher-level operations\n\nThe `Do` library makes doing higher-level abstractions easy.  All of these helpers are themselves continuables so you can attach callbacks by calling the returned, curried function.\n\n### Do.parallel(actions) {...}\n\nTakes an array of actions and runs them all in parallel. You can either pass in an array of actions, or several actions as function arguments.\n\n - If you pass in an array, then the output will be an array of all the results\n - If you pass in separate arguments, then the output will have several arguments.\n \n**Example:**\n\n    // Multiple arguments\n    Do.parallel(\n      Do.read(\"/etc/passwd\"),\n      Do.read(__filename)\n    )(function (passwd, self) {\n      // Do something\n    }, errorHandler);\n\n    // Single argument\n    var actions = [\n      Do.read(\"/etc/passwd\"),\n      Do.read(\"__filename\")\n    ];\n    Do.parallel(actions)(function (results) {\n      // Do something\n    }, errorHandler);\n \n### Do.chain(actions) {...}\n\nChains together several actions feeding the output of the first to the input of the second and the final output to the continuables callback.\n\n**Example:**\n\n    // Multiple arguments\n    Do.chain(\n      Do.read(__filename),\n      function (text) { \n        return Do.save(\"newfile\", text);\n      },\n      function () {\n        return Do.stat(\"newfile\");\n      }\n    )(function (stat) {\n      // Do something\n    }, errorHandler);\n\n    // Single argument\n    var actions = [\n      Do.read(__filename),\n      function (text) { \n        return Do.save(\"newfile\", text);\n      },\n      function () {\n        return Do.stat(\"newfile\");\n      }\n    ];\n    Do.chain(actions)(function (stat) {\n      // Do something\n    }, errorHandler);\n\n### Do.map(array, fn) {...}\n\nTakes an array and does an array map over it using the async callback `fn`. The signature of `fn` is `function fn(item, callback, errback)` or any regular continuable.\n\n**Example:**\n\n    // Direct callback filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    function loadFile(filename, callback, errback) {\n      fs.read(filename)(function (data) {\n        callback([filename, data]);\n      }, errback);\n    }\n    Do.map(files, loadFile)(function (contents) {\n      // Do something\n    }, errorHandler);\n    \n    // continuable based filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    Do.map(files, fs.read)(function (contents) {\n      // Do something\n    }, errorHandler);\n\n### Do.filter(array, fn) {...}\n\nTakes an array and does an array filter over it using the async callback `fn`. The signature of `fn` is `function fn(item, callback, errback)` or any regular continuable.\n\n**Example:**\n\n    // Direct callback filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    function isFile(filename, callback, errback) {\n      fs.stat(filename)(function (stat) {\n        callback(stat.isFile());\n      }, errback);\n    }\n    Do.filter(files, isFile)(function (filtered_files) {\n      // Do something\n    }, errorHandler);\n\n    // Continuable based filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    function isFile(filename) { return function (callback, errback) {\n      fs.stat(filename)(function (stat) {\n        callback(stat.isFile());\n      }, errback);\n    }}\n    Do.filter(files, isFile)(function (filtered_files) {\n      // Do something\n    }, errorHandler);\n\n### Do.filterMap(array, fn) {...}\n\nTakes an array and does a combined filter and map over it.  If the result\nof an item is undefined, then it's filtered out, otherwise it's mapped in.\nThe signature of `fn` is `function fn(item, callback, errback)` or any regular continuable.\n\n**Example:**\n\n    // Direct callback filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    function check_and_load(filename, callback, errback) {\n      fs.stat(filename)(function (stat) {\n        if (stat.isFile()) {\n          loadFile(filename, callback, errback);\n        } else {\n          callback();\n        }\n      }, errback);\n    }\n    Do.filterMap(files, check_and_load)(function (filtered_files_with_data) {\n      // Do something\n    }, errorHandler);\n\n    // Continuable based filter\n    var files = ['users.json', 'pages.json', 'products.json'];\n    function check_and_load(filename) { return function (callback, errback) {\n      fs.stat(filename)(function (stat) {\n        if (stat.isFile()) {\n          loadFile(filename, callback, errback);\n        } else {\n          callback();\n        }\n      }, errback);\n    }}\n    Do.filterMap(files, check_and_load)(function (filtered_files_with_data) {\n      // Do something\n    }, errorHandler);\n\n## Using with node libraries\n\nDo has a super nifty `Do.convert` function that takes a library and converts it to use Do style continuables.  For example, if you wanted to use `fs.readFile` and `fs.writeFile`, then you would do this:\n\n    var fs = Do.convert(require('fs'), ['readFile', 'writeFile']);\n\nDo will give you a copy of `fs` that has `readFile` and `writeFile` converted to Do style.  It's that easy!\n\n### For library writers\n\nAll async functions in node follow a common interface:\n\n    method(arg1, arg2, arg3, ..., callback)\n\nWhere `callback` is of the form:\n\n    callback(err, result1, result2, ...)\n\nThis is done to keep node simple and to allow for interoperability between the various async abstractions like Do continuables and CommonJS promises.\n\nIf you're writing a library, make sure to export all your async functions following the node interface.  Then anyone using your library can know what format to expect.\n\n## Future TODOs\n\n - Make some sort of helper that makes it easy to call any function regardless of it's sync or async status.  This is tricky vs. promises since our return value is just a regular function, not an instance of something.\n\n## License\n\nDo is [licensed][] under the [MIT license][].\n\n[MIT license]: http://creativecommons.org/licenses/MIT/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fdo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreationix%2Fdo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fdo/lists"}