{"id":13663171,"url":"https://github.com/jeffreylanters/unity-promises","last_synced_at":"2025-04-25T13:32:03.886Z","repository":{"id":51286260,"uuid":"163857435","full_name":"jeffreylanters/unity-promises","owner":"jeffreylanters","description":"Promises provide a simpler alternative for executing, composing, and managing asynchronous operations when compared to traditional callback-based approaches. They also allow you to handle asynchronous errors using approaches that are similar to synchronous try/catch.","archived":true,"fork":false,"pushed_at":"2021-09-07T11:33:21.000Z","size":408,"stargazers_count":38,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-10T19:34:24.763Z","etag":null,"topics":["async","promise","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","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/jeffreylanters.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"jeffreylanters"}},"created_at":"2019-01-02T15:23:13.000Z","updated_at":"2023-08-12T17:28:39.000Z","dependencies_parsed_at":"2022-08-25T14:40:09.093Z","dependency_job_id":null,"html_url":"https://github.com/jeffreylanters/unity-promises","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreylanters%2Funity-promises","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreylanters%2Funity-promises/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreylanters%2Funity-promises/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffreylanters%2Funity-promises/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeffreylanters","download_url":"https://codeload.github.com/jeffreylanters/unity-promises/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250825021,"owners_count":21493379,"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","promise","unity"],"created_at":"2024-08-02T05:02:19.919Z","updated_at":"2025-04-25T13:31:58.822Z","avatar_url":"https://github.com/jeffreylanters.png","language":"C#","funding_links":["https://github.com/sponsors/jeffreylanters","https://paypal.me/jeffreylanters"],"categories":["C\\#","C#"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n![readme splash](https://raw.githubusercontent.com/jeffreylanters/unity-promises/master/.github/WIKI/repository-readme-splash.png)\n\n[![license](https://img.shields.io/badge/mit-license-red.svg?style=for-the-badge)](https://github.com/jeffreylanters/unity-promises/blob/master/LICENSE.md)\n[![openupm](https://img.shields.io/npm/v/nl.elraccoone.promises?label=UPM\u0026registry_uri=https://package.openupm.com\u0026style=for-the-badge\u0026color=232c37)](https://openupm.com/packages/nl.elraccoone.promises/)\n[![build](https://img.shields.io/badge/build-passing-brightgreen.svg?style=for-the-badge)](https://github.com/jeffreylanters/unity-promises/actions)\n[![deployment](https://img.shields.io/badge/state-success-brightgreen.svg?style=for-the-badge)](https://github.com/jeffreylanters/unity-promises/deployments)\n[![stars](https://img.shields.io/github/stars/jeffreylanters/unity-promises.svg?style=for-the-badge\u0026color=fe8523\u0026label=stargazers)](https://github.com/jeffreylanters/unity-promises/stargazers)\n[![awesome](https://img.shields.io/badge/listed-awesome-fc60a8.svg?style=for-the-badge)](https://github.com/jeffreylanters/awesome-unity-packages)\n[![size](https://img.shields.io/github/languages/code-size/jeffreylanters/unity-promises?style=for-the-badge)](https://github.com/jeffreylanters/unity-promises/blob/master/Runtime)\n[![sponsors](https://img.shields.io/github/sponsors/jeffreylanters?color=E12C9A\u0026style=for-the-badge)](https://github.com/sponsors/jeffreylanters)\n[![donate](https://img.shields.io/badge/donate-paypal-F23150?style=for-the-badge)](https://paypal.me/jeffreylanters)\n\nPromises provide a simpler alternative for executing, composing, and managing asynchronous operations when compared to traditional callback-based approaches. They also allow you to handle asynchronous errors using approaches that are similar to synchronous try/catch.\n\n[**Installation**](#installation) \u0026middot;\n[**Documentation**](#documentation) \u0026middot;\n[**License**](./LICENSE.md)\n\n**Made with \u0026hearts; by Jeffrey Lanters**\n\n\u003c/div\u003e\n\n# Installation\n\n### Using the Unity Package Manager\n\nInstall the latest stable release using the Unity Package Manager by adding the following line to your `manifest.json` file located within your project's Packages directory, or by adding the Git URL to the Package Manager Window inside of Unity.\n\n```json\n\"nl.elraccoone.promises\": \"git+https://github.com/jeffreylanters/unity-promises\"\n```\n\n### Using OpenUPM\n\nThe module is availble on the OpenUPM package registry, you can install the latest stable release using the OpenUPM Package manager's Command Line Tool using the following command.\n\n```sh\nopenupm add nl.elraccoone.promises\n```\n\n# Documentation\n\nA Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.\n\nA Promise is in one of these states:\n\n- pending: initial state, neither fulfilled nor rejected.\n- fulfilled: meaning that the operation completed successfully.\n- rejected: meaning that the operation failed.\n\nA pending promise can either be fulfilled with a value, or rejected with a reason (error). When either of these options happens, the associated handlers queued up by a promise's then method are called. (If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached.)\n\n## Syntax\n\nA function that is passed with the arguments resolve and reject. The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object). The resolve and reject functions, when called, resolve or reject the promise, respectively. The executor normally initiates some asynchronous work, and then, once that completes, either calls the resolve function to resolve the promise or else rejects it if an error occurred. If an error is thrown in the executor function, the promise is rejected. The return value of the executor is ignored.\n\n```cs\nnew Promise ((resolve, reject) =\u003e { /* ... */ });\nnew Promise\u003cResolveType\u003e ((resolve, reject) =\u003e { /* ... */ });\nnew Promise\u003cResolveType, RejectType\u003e ((resolve, reject) =\u003e { /* ... */ });\n```\n\n## Creating a Promise\n\nA Promise object is created using the new keyword and its constructor. This constructor takes as its argument a function, called the \"executor function\". This function should take two functions as parameters. The first of these functions (resolve) is called when the asynchronous task completes successfully and returns the results of the task as a value. The second (reject) is called when the task fails, and returns the reason for failure, which is typically an error object.\n\n```cs\npublic Promise LoadSomeData () {\n  // Return a new void promise and assign the executor.\n  return new Promise ((resolve, reject) =\u003e {\n    // do something asynchronous which eventually calls either:\n    resolve (); // to fulfill\n    reject (new Exception (\"Failed\")); // or reject\n  });\n}\n\npublic Promise\u003cint\u003e LoadSomeData () {\n  // Return a new promise with a generic resolve type and assign the executor.\n  return new Promise\u003cint\u003e ((resolve, reject) =\u003e {\n    // do something asynchronous which eventually calls either:\n    resolve (100); // to fulfill\n    reject (new Exception (\"Not found!\")); // or reject\n  });\n}\n\npublic Promise\u003cstring, CustomException\u003e LoadSomeData () {\n  // Return a new promise with a generic resolve and reject type and assign the executor.\n  return new Promise\u003cstring, CustomException\u003e ((resolve, reject) =\u003e {\n    // do something asynchronous which eventually calls either:\n    resolve (\"Hello World!\"); // to fulfill\n    reject (new CustomException ()); // or reject\n  });\n}\n```\n\n## Using a Promise\n\n### Using classic Then/Catch callbacks\n\nExecute your function and return a promise. You can use the Promise.Then() and Promise.Catch() methods to set actions that should be triggered when the promise resolves or failes. These methods return promises so they can be chained.\n\n```cs\npublic void Start () {\n  this.LoadSomeData()\n    .Then (value =\u003e { /* ... */ })\n    .Catch (reason =\u003e { /* ... */ })\n    .Finally (() =\u003e { /* ... */ });\n}\n```\n\n### Using Async/Await methods\n\nWhen chaining multiple promises after one another or when simply wanting to prevent a lot of nested callbacks, use the async await logic to keep things simple. There are two ways of doing so, the simplest way does not require any changes on the promise's creation side. A basic implementation could be as following.\n\n```cs\npublic async void Start () {\n  try {\n    var value = await this.LoadSomeData ().Async ();\n    // \"Then\"\n  } catch (Exception exception) {\n    // \"Catch\"\n  }\n  // \"Finally\"\n}\n```\n\nAnother way would be to wrap the Async before returning it as a promise, this way the promise can be awaited right away when invoking it. But this also means it can no longer be used using callbacks. A basic implementation could be as following.\n\n```csharp\npublic async Task\u003cstring\u003e LoadSomeData () {\n  // Return and await a new Task with a generic type.\n  return await new Promise\u003cstring\u003e ((resolve, reject) =\u003e {\n    // do something asynchronous which eventually calls either:\n    resolve (\"Hello World!\"); // to fulfill\n    reject (new Exception (\"Whoops\")); // or reject\n  }).Async();\n}\n\npublic async void Start () {\n  var value = await this.LoadSomeData ();\n  // ...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffreylanters%2Funity-promises","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffreylanters%2Funity-promises","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffreylanters%2Funity-promises/lists"}