{"id":13601206,"url":"https://github.com/Real-Serious-Games/C-Sharp-Promise","last_synced_at":"2025-04-11T03:32:39.347Z","repository":{"id":41548589,"uuid":"25947457","full_name":"Real-Serious-Games/C-Sharp-Promise","owner":"Real-Serious-Games","description":"Promises library for C# for management of asynchronous operations.","archived":false,"fork":false,"pushed_at":"2020-05-11T14:35:39.000Z","size":2375,"stargazers_count":1223,"open_issues_count":12,"forks_count":149,"subscribers_count":65,"default_branch":"master","last_synced_at":"2025-04-07T08:07:19.152Z","etag":null,"topics":["async-operation","c-sharp","game-development","promise","unity","unity3d"],"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/Real-Serious-Games.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-30T00:20:30.000Z","updated_at":"2025-03-31T14:07:47.000Z","dependencies_parsed_at":"2022-07-07T16:51:18.559Z","dependency_job_id":null,"html_url":"https://github.com/Real-Serious-Games/C-Sharp-Promise","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Real-Serious-Games%2FC-Sharp-Promise","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Real-Serious-Games%2FC-Sharp-Promise/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Real-Serious-Games%2FC-Sharp-Promise/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Real-Serious-Games%2FC-Sharp-Promise/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Real-Serious-Games","download_url":"https://codeload.github.com/Real-Serious-Games/C-Sharp-Promise/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248335579,"owners_count":21086622,"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-operation","c-sharp","game-development","promise","unity","unity3d"],"created_at":"2024-08-01T18:00:58.459Z","updated_at":"2025-04-11T03:32:34.328Z","avatar_url":"https://github.com/Real-Serious-Games.png","language":"C#","funding_links":[],"categories":["Open Source Repositories","C# #","C\\#","Open Source Packages","Scripting"],"sub_categories":["Utilities"],"readme":"# C-Sharp-Promise [![Build Status](https://travis-ci.org/Real-Serious-Games/C-Sharp-Promise.svg)](https://travis-ci.org/Real-Serious-Games/C-Sharp-Promise) [![NuGet](https://img.shields.io/nuget/v/RSG.Promise.svg)](https://www.nuget.org/packages/RSG.Promise/) #\n\n\u003ca href=\"https://promisesaplus.com/\"\u003e\n    \u003cimg src=\"https://promisesaplus.com/assets/logo-small.png\" alt=\"Promises/A+ logo\"\n         title=\"Promises/A+ 1.0 compliant\" align=\"right\" /\u003e\n\u003c/a\u003e\n\nPromises library for C# for management of asynchronous operations.\n\nInspired by JavaScript promises, but slightly different.\n\nUsed by [Real Serious Games](https://github.com/Real-Serious-Games/C-Sharp-Promise) for building serious games and simulations on Unity3d.\n\nIf you are interested in using promises for game development and Unity please see [this article](http://www.what-could-possibly-go-wrong.com/promises-for-game-development/).\n\n## Recent Updates\n\n- v3.0 (15 Feburary 2018)\n    - *Finally* has been modified to work in a way consistent to [Promise.prototype.finally()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally) in JavaScript.\n    - Added support for reporting progress in a promise.\n    - Signed assembly with a strong name.\n    - Errors throw custom exception types rather than generic ones.\n    - Modified some overloads of *Then* that didn't make sense.\n- v2.0 (4 December 2017)\n    - *Then* functions chained after a *Catch* are now run after the exception is handled rather than being terminated\n    - *Catch* can return a value which will be passed into the next *Then*\n    - The *onResolved* callback of *Then* can now also return a value which is passed to the next promise in the same way\n    - Added *elapsedUpdates* property to the TimeData struct used by PromiseTimer\n- v1.3 (28 October 2017)\n    - Added Cancel method to PromiseTimer\n    - Implemented an overload of Promise.All that works on Tuples of multiple types\n    - Implemented Finally method\n    - Removed dependency on RSG.Toolkit\n- v1.2 (8 March 2015)\n    - *Transform* function has been renamed to *Then* (another overload of *Then*).\n\n## Projects using this library\n- **[RestClient for Unity 🤘](https://github.com/proyecto26/RestClient)**\n\n## Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [Understanding Promises](#understanding-promises)\n- [Promises/A+ Spec](#promisesa-spec)\n- [Getting the DLL](#getting-the-dll)\n- [Getting the Code](#getting-the-code)\n- [Creating a Promise for an Async Operation](#creating-a-promise-for-an-async-operation)\n- [Creating a Promise, Alternate Method](#creating-a-promise-alternate-method)\n- [Waiting for an Async Operation to Complete](#waiting-for-an-async-operation-to-complete)\n- [Chaining Async Operations](#chaining-async-operations)\n- [Transforming the Results](#transforming-the-results)\n- [Error Handling](#error-handling)\n- [Unhandled Errors](#unhandled-errors)\n- [Progress reporting](#progress-reporting)\n- [Promises that are already Resolved/Rejected](#promises-that-are-already-resolvedrejected)\n- [Interfaces](#interfaces)\n- [Combining Multiple Async Operations](#combining-multiple-async-operations)\n- [Chaining Multiple Async Operations](#chaining-multiple-async-operations)\n- [Racing Asynchronous Operations](#racing-asynchronous-operations)\n- [Chaining Synchronous Actions that have no Result](#chaining-synchronous-actions-that-have-no-result)\n- [Promises that have no Results (a non-value promise)](#promises-that-have-no-results-a-non-value-promise)\n- [Convert a value promise to a non-value promise](#convert-a-value-promise-to-a-non-value-promise)\n- [Running a Sequence of Operations](#running-a-sequence-of-operations)\n- [Combining Parallel and Sequential Operations](#combining-parallel-and-sequential-operations)\n- [Weighted averaging of progress on multiple promises](#weighted-averaging-of-progress-on-multiple-promises)\n- [PromiseTimer class](#promisetimer-class)\n  - [PromiseTimer.WaitFor](#promisetimerwaitfor)\n  - [PromiseTimer.WaitUntil](#promisetimerwaituntil)\n  - [PromiseTimer.WaitWhile](#promisetimerwaitwhile)\n  - [TimeData struct](#timedata-struct)\n- [Examples](#examples)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Understanding Promises\n\nTo learn about promises:\n\n- [Promises on Wikpedia](http://en.wikipedia.org/wiki/Futures_and_promises)\n- [Good overview](https://www.promisejs.org/)\n- [Mozilla](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)\n\n## Promises/A+ Spec\n\nThis promise library conforms to the [Promises/A+ Spec](https://promisesaplus.com/) (at least, as far as is possible with C#):\n\n## Getting the DLL\n\nThe DLL can be installed via nuget. Use the Package Manager UI or console in Visual Studio or use nuget from the command line.\n\nSee here for instructions on installing a package via nuget: http://docs.nuget.org/docs/start-here/using-the-package-manager-console\n\nThe package to search for is *RSG.Promise*.\n\n## Getting the Code\n\nYou can get the code by cloning the github repository. You can do this in a UI like SourceTree or you can do it from the command line as follows:\n\n    git clone https://github.com/Real-Serious-Games/C-Sharp-Promise.git\n\nAlternately, to contribute please fork the project in github.\n\n## Creating a Promise for an Async Operation ##\n\nReference the DLL and import the namespace:\n```cs\nusing RSG;\n```\nCreate a promise before you start the async operation:\n```cs\nvar promise = new Promise\u003cstring\u003e();\n```\nThe type of the promise should reflect the result of the async op.\n\nThen initiate your async operation and return the promise to the caller.\n\nUpon completion of the async op the promise is resolved:\n```cs\npromise.Resolve(myValue);\n```\nThe promise is rejected on error/exception:\n```cs\npromise.Reject(myException);\n```\nTo see it in context, here is an example function that downloads text from a URL. The promise is resolved when the download completes. If there is an error during download, say *unresolved domain name*, then the promise is rejected:\n\n```cs\npublic IPromise\u003cstring\u003e Download(string url)\n{\n    var promise = new Promise\u003cstring\u003e();    // Create promise.\n    using (var client = new WebClient())\n    {\n        client.DownloadStringCompleted +=   // Monitor event for download completed.\n            (s, ev) =\u003e\n            {\n                if (ev.Error != null)\n                {\n                    promise.Reject(ev.Error);   // Error during download, reject the promise.\n                }\n                else\n                {\n                    promise.Resolve(ev.Result); // Downloaded completed successfully, resolve the promise.\n                }\n            };\n\n        client.DownloadStringAsync(new Uri(url), null); // Initiate async op.\n    }\n\n    return promise; // Return the promise so the caller can await resolution (or error).\n}\n```\n\n## Creating a Promise, Alternate Method\n\nThere is another way to create a promise that replicates the JavaScript convention of passing a *resolver* function into the constructor. The resolver function is passed functions that resolve or reject the promise. This allows you to express the previous example like this:\n\n```cs\nvar promise = new Promise\u003cstring\u003e((resolve, reject) =\u003e\n{\n    using (var client = new WebClient())\n    {\n        client.DownloadStringCompleted +=   // Monitor event for download completed.\n            (s, ev) =\u003e\n            {\n                if (ev.Error != null)\n                {\n                    reject(ev.Error);       // Error during download, reject the promise.\n                }\n                else\n                {\n                    resolve(ev.Result);     // Downloaded completed successfully, resolve the promise.\n                }\n            };\n\n        client.DownloadStringAsync(new Uri(url), null); // Initiate async op.\n    }\n});\n```\n\n## Waiting for an Async Operation to Complete ##\n\nThe simplest usage is to register a completion handler to be invoked on completion of the async op:\n```cs\nDownload(\"http://www.google.com\")\n    .Then(html =\u003e\n        Console.WriteLine(html)\n    );\n```\n\nThis snippet downloads the front page from Google and prints it to the console.\n\nFor all but the most trivial applications you will also want to register an error hander:\n```cs\nDownload(\"http://www.google.com\")\n    .Then(html =\u003e\n        Console.WriteLine(html)\n    )\n    .Catch(exception =\u003e\n        Console.WriteLine(\"An exception occured while downloading!\")\n    );\n```\n\nThe chain of processing for a promise ends as soon as an error/exception occurs. In this case when an error occurs the *Catch* handler would be called, but not the *Done* handler. If there is no error, then only *Done* is called.\n\n## Chaining Async Operations ##\n\nMultiple async operations can be chained one after the other using *Then*:\n```cs\nDownload(\"http://www.google.com\")\n    .Then(html =\u003e\n        return Download(ExtractFirstLink(html)) // Extract the first link and download it.\n    )\n    .Then(firstLinkHtml =\u003e\n        Console.WriteLine(firstLinkHtml)\n    )\n    .Catch(exception =\u003e\n        Console.WriteLine(\"An exception occured while downloading!\")\n    );\n```\n\nHere we are chaining another download onto the end of the first download. The first link in the html is extracted and we then download that. *Then* expects the return value to be another promise. The chained promise can have a different *result type*.\n\n## Transforming the Results ##\n\nSometimes you will want to simply transform or modify the resulting value without chaining another async operation.\n```cs\nDownload(\"http://www.google.com\")\n    .Then(html =\u003e\n        return ExtractAllLinks(html))   // Extract all links and return an array of strings.\n    )\n    .Then(links =\u003e                      // The input here is an array of strings.\n        foreach (var link in links)\n        {\n            Console.WriteLine(link);\n        }\n    );\n```\n\nAs is demonstrated the type of the value can also be changed during transformation. In the previous snippet a `Promise\u003cstring\u003e` is transformed to a `Promise\u003cstring[]\u003e`.\n\n## Error Handling\n\nAn error raised in a callback aborts the function and all subsequent callbacks in the chain:\n```cs\npromise.Then(v =\u003e Something())   // \u003c--- An error here aborts all subsequent callbacks...\n    .Then(v =\u003e SomethingElse())\n    .Then(v =\u003e AnotherThing())\n    .Catch(e =\u003e HandleError(e))  // \u003c--- Until the error handler is invoked here.\n```\n\n## Unhandled Errors\n\nWhen `Catch` is omitted exceptions go silently unhandled. This is an acknowledged issue with the Promises pattern.\n\nWe handle this in a similar way to the JavaScript [Q](http://documentup.com/kriskowal/q) library. The `Done` method is used to terminate a chain, it registers a default catch handler that propagates unhandled exceptions to a default error handling mechanism that can be hooked into by the user.\n\nTerminating a Promise chain using `Done`:\n```cs\npromise.Then(v =\u003e Something())\n    .Then(v =\u003e SomethingElse())\n    .Then(v =\u003e AnotherThing())\n    .Done();    // \u003c--- Terminate the pipeline and propagate unhandled exceptions.\n```\n\nTo use the `Done` you must apply the following rule: When you get to the end of a chain of promises, you should either return the last promise or end the chain by calling `Done`.\n\nTo hook into the unhandled exception stream:\n```cs\nPromise.UnhandledException += Promise_UnhandledException;\n```\n\nThen forward the exceptions to your own logging system:\n```cs\nprivate void Promise_UnhandledException(object sender, ExceptionEventArgs e)\n{\n    Log.Error(e.Exception, \"An unhandled promises exception occured!\");\n}\n```\n\n## Progress reporting\n\nPromises can additionally report their progress towards completion, allowing the implementor to give the user feedback on the asynchronous operation. The general convention is to report progress as a value from 0 to 1.\n\nFor this, you can either call `Progress` in the promise definition chain or add a third parameter to the `Then` method.\n\nListening for progress reporting from a promise using `Progress`:\n```cs\nvar promise = new Promise();\npromise.Progress((progress) =\u003e Log.Info(\"Current progress is \" + (100f * progress) + \"%\"));\n```\n\nListening for progress on a `Then` call:\n```cs\nvar promiseA = new Promise();\nvar promiseB = new Promise();\npromise\n    .Then(() =\u003e promiseB, null, (progress) =\u003e Log.Info(\"promiseA made progress: \" + progress))\n    .Progress(progress =\u003e Log.Info(\"promiseB made progress: \" + progress));\n```\n\nIn order to report progress for a promise, you need to call the `ReportProgress` method:\n```cs\nvar promise = new Promise();\npromise.ReportProgress(0.5f); // Report a 50% completion\n```\n\n## Promises that are already Resolved/Rejected\n\nFor convenience or testing you will at some point need to create a promise that *starts out* in the resolved or rejected state. This is easy to achieve using *Resolved* and *Rejected* functions:\n```cs\nvar resolvedPromise = Promise\u003cstring\u003e.Resolved(\"some result\");\n\nvar rejectedPromise = Promise\u003cstring\u003e.Rejected(someException);\n```\n\n## Interfaces ##\n\nThe class *Promise\u003cT\u003e* implements the following interfaces:\n\n- `IPromise\u003cT\u003e` Interface to await promise resolution.\n- `IPendingPromise\u003cT\u003e` Interface that can resolve or reject the promise.\n\n## Combining Multiple Async Operations ##\n\nThe *All* function combines multiple async operations to run in parallel. It converts a collection of promises or a variable length parameter list of promises into a single promise that yields a collection.\n\nSay that each promise yields a value of type *T*, the resulting promise then yields a collection with values of type *T*.\n\nHere is an example that extracts links from multiple pages and merges the results:\n```cs\nvar urls = new List\u003cstring\u003e();\nurls.Add(\"www.google.com\");\nurls.Add(\"www.yahoo.com\");\n\nPromise\u003cstring[]\u003e\n    .All(urls.Select(url =\u003e Download(url)))  // Download each URL.\n    .Then(pages =\u003e              // Receives collection of downloaded pages.\n        pages.SelectMany(\n            page =\u003e ExtractAllLinks(page) // Extract links from all pages then flatten to single collection of links.\n        )\n    )\n    .Done(links =\u003e              // Receives the flattened collection of links from all pages at once.\n    {\n        foreach (var link in links)\n        {\n            Console.WriteLine(link);\n        }\n    });\n```\n\nWhen listening for progress events in an All operation, the progress that you will receive will be the average of all the progress values reported by all the given promises.\n\n## Chaining Multiple Async Operations\n\nThe *ThenAll* function is a convenient way of chaining multiple promise onto an existing promise:\n```cs\npromise\n    .Then(result =\u003e SomeAsyncOperation(result)) // Chain a single async operation\n    .ThenAll(result =\u003e                          // Chain multiple async operations.\n        new IPromise\u003cstring\u003e[]                  // Return an enumerable of promises.\n        {\n            SomeAsyncOperation1(result),\n            SomeAsyncOperation2(result),\n            SomeAsyncOperation3(result)\n        }\n    )\n    .Done(collection =\u003e ...);                   // Final promise resolves\n                                                // with a collection of values\n                                                // when all operations have completed.\n```\n\n## Racing Asynchronous Operations\n\nThe *Race* and *ThenRace* functions are similar to the *All* and *ThenAll* functions, but it is the first async operation that completes that wins the race and it's value resolves the promise.\n```cs\npromise\n    .Then(result =\u003e SomeAsyncOperation(result)) // Chain an async operation.\n    .ThenRace(result =\u003e                         // Race multiple async operations.\n        new IPromise\u003cstring\u003e[]                  // Return an enumerable of promises.\n        {\n            SomeAsyncOperation1(result),\n            SomeAsyncOperation2(result),\n            SomeAsyncOperation3(result)\n        }\n    )\n    .Done(result =\u003e ...);                       // The result has come from whichever of\n                                                // the async operations completed first.\n```\n\nWhen listening for progress events in a race operation, the progress that you will receive will be the maximum of those reported by all the given promises.\n\n## Chaining Synchronous Actions that have no Result\n\nThe *Then* function can be used to chain synchronous operations that yield no result.\n```cs\nvar promise = ...\npromise\n    .Then(result =\u003e SomeAsyncOperation(result)) \t// Chain an async operation.\n    .Then(result =\u003e Console.WriteLine(result))    \t// Chain a sync operation that yields no result.\n    .Done(() =\u003e ...);  // No result is passed because the previous operation returned nothing.\n```\n\n## Promises that have no Results (a non-value promise)\n\nWhat about a promise that has no result? This represents an asynchronous operation that promises only to complete, it doesn't promise to yield any value as a result. I call this a non-value promise, as opposed to a value promise, which is a promise that does yield a value. This might seem like a curiousity but it is actually very useful for sequencing visual effects.\n\n`Promise` is very similar to `Promise\u003cT\u003e` and implements the similar interfaces: `IPromise` and `IPendingPromise`.\n\n`Promise\u003cT\u003e` functions that affect the resulting value have no relevance for the non-value promise and have been removed.\n\nAs an example consider the chaining of animation and sound effects as we often need to do in *game development*:\n```cs\nRunAnimation(\"Foo\")                         // RunAnimation returns a promise that\n    .Then(() =\u003e RunAnimation(\"Bar\"))        // is resolved when the animation is complete.\n    .Then(() =\u003e PlaySound(\"AnimComplete\"));\n```\n\n## Convert a value promise to a non-value promise\n\nFrom time to time you might want to convert a value promise to a non-value promise or vice versa. Both `Promise` and `Promise\u003cT\u003e` have overloads of `Then` and `ThenAll` that do this conversion. You just need to return the appropriate type of promise (for `Then`) or enumerable of promises (for `ThenAll`).\n\nAs an example consider a recursive link extractor and file downloader function:\n```cs\npublic IPromise DownloadAll(string url)\n{\n    return DownloadURL(url)                 // Yields a value, the HTML text downloaded.\n        .Then(html =\u003e ExtractLinks(html))   // Convert HTML into an enumerable of links.\n        .ThenAll(links =\u003e                   // Process each link.\n        {\n            // Determine links that should be followed, then follow them.\n            var linksToFollow = links.Where(link =\u003e IsLinkToFollow(link));\n            var linksFollowing = linksToFollow.Select(link =\u003e DownloadAll(link));\n\n            // Determine links that are files to be downloaded, then download them.\n            var linksToDownload = links.Where(link =\u003e IsLinkToDownload(link));\n            var linksDownloading = linksToDownload.Select(link =\u003e DownloadFile(link));\n\n            // Return an enumerable of promises.\n            // This combines the recursive link following and any files we want to download.\n            // Because we are returning an enumerable of non-value promises, the resulting\n            // chained promises is also non-value.\n            return linksToFollow.Concat(linksDownloading);\n        });\n}\n```\n\nUsage:\n```cs\nDownloadAll(\"www.somewhere.com\")\n    .Done(() =\u003e\n        Console.WriteLine(\"Recursive download completed.\");\n    );\n```\n\n## Running a Sequence of Operations\n\nThe `Sequence` and `ThenSequence` functions build a single promise that wraps multiple sequential operations that will be invoked one after the other.\n\nMultiple promise-yielding functions are provided as input, these are chained one after the other and wrapped in a single promise that is resolved once the sequence has completed.\n```cs\nvar sequence = Promise.Sequence(\n    () =\u003e RunAnimation(\"Foo\"),\n    () =\u003e RunAnimation(\"Bar\"),\n    () =\u003e PlaySound(\"AnimComplete\")\n);\n```\n\nThe inputs can also be passed as a collection:\n```cs\nvar operations = ...\nvar sequence = Promise.Sequence(operations);\n```\n\nThis might be used, for example, to play a variable length collection of animations based on data:\n```cs\nvar animationNames = ... variable length array of animation names loaded from data...\nvar animations = animationNames.Select(animName =\u003e (Func\u003cIPromise\u003e)(() =\u003e RunAnimation(animName)));\nvar sequence = Promise.Sequence(animations);\nsequence\n    .Done(() =\u003e\n    {\n        // All animations have completed in sequence.\n    });\n```\n\nUnfortunately we find that we have reached the limits of what is possible with C# type inference, hence the use of the ugly cast `(Func\u003cIPromise\u003e)`.\n\nThe cast can easily be removed by converting the inner anonymous function to an actual function which I'll call `PrepAnimation`:\n```cs\nprivate Func\u003cIPromise\u003e PrepAnimation(string animName)\n{\n    return () =\u003e RunAnimation(animName);\n}\n\nvar animations = animationNames.Select(animName =\u003e PrepAnimation(animName));\nvar sequence = Promise.Sequence(animations);\nsequence\n    .Done(() =\u003e\n    {\n        // All animations have completed in sequence.\n    });\n```\n\nHoly cow... we've just careened into [functional programming](http://en.wikipedia.org/wiki/Functional_programming) territory, herein lies very powerful and expressive programming techniques.\n\n## Combining Parallel and Sequential Operations\n\nWe can easily combine sequential and parallel operations to build very expressive logic.\n```cs\nPromise.Sequence(               // Play operations 1 and 2 sequently.\n    () =\u003e Promise.All(          // Operation 1: Play animation and sound at same time.\n        RunAnimation(\"Foo\"),\n        PlaySound(\"Bar\")\n    ),\n    () =\u003e Promise.All(\n        RunAnimation(\"One\"),    // Operation 2: Play animation and sound at same time.\n        PlaySound(\"Two\")\n    )\n);\n```\n\nI'm starting to feel like we are defining behavior trees.\n\n## Weighted averaging of progress on multiple promises\n\nIf you have a promise that comprises a sequence of other promises, you might want to report the total progress for these, and even give more weight to the progress of some promise over another. In this example, we are first downloading an asset from some URL and then we are loading the downloaded asset into memory. We consider that the time it takes to download the asset will be an 80% of the total time, while the time to load it into memory is a 20%:\n```cs\nvar promise = new Promise();\n\nDownload(url)\n    .Progress((downloadProgress) =\u003e promise.ReportProgress(0.8f * downloadProgress))\n    .Then((asset) =\u003e LoadAssetIntoMemory(asset))\n    .Progress((loadProgress) =\u003e promise.ReportProgress(0.8f + 0.2f * loadProgress))\n    .Then(() =\u003e promise.Resolve())\n    .Catch((ex) =\u003e promise.Reject(ex));\n\nreturn promise;\n```\n\n## PromiseTimer class\n\nThe promise timer is not part of the Promises/A+ standard but is a utility that makes it possible to create promises that check if a condition is met each time the promise timer is updated. A common usage of this is in games where the promise timer is updated each frame.\n\nTo use it, create an instance of the promise timer and call its `Update` method in your main loop:\n```cs\nclass Example\n{\n    private IPromiseTimer promiseTimer;\n\n    Example()\n    {\n        promiseTimer = new PromiseTimer();\n    }\n\n    // Run once for every frame - equivilant to Update() in Unity\n    void MainLoop()\n    {\n        // deltaTime is equal to the time since the last MainLoop\n        promiseTimer.Update(Time.deltaTime);\n\n        // Process your other logic here\n    }\n}\n```\n\nNote that usually it is best to call `PromiseTimer.Update` *before* your other logic, otherwise you may have unintended behaviour such as promises that are supposed to take a very short time resolving in the same update loop as they were created in.\n\n### PromiseTimer.WaitFor\n\nThis method creates a promise that resolves after the specified amount of time in seconds has passed. Time is calculated as the sum of the delta values passed into `PromiseTimer.Update`\n```cs\nIPromise LogAfterFourSeconds()\n{\n    return promiseTimer.WaitFor(4f)\n        .Then(() =\u003e Console.Log(\"4 seconds have passed!\"));\n}\n```\n\n### PromiseTimer.WaitUntil\n\nWaitUntil takes a predicate to check each update and resolves once the predicate returns true. This predicate function is passed a `TimeData` object, which just contains the most recent frame's `deltaTime` and `elapsedTime` which is the total amount of time since the promise was created.\n```cs\nIPromise FadeOut(float duration)\n{\n    return promiseTimer.WaitUntil(timeData =\u003e\n    {\n        // Here we are using the amount of elapsed time to calculate what the current\n        // fade value should be (between 0 and 1).\n        // Since we're fading our we should be going from 0 (not faded) to 1 (full)\n        var fadeAmount = Mathf.Clamp01(timeData.elapsedTime / duration);\n        SetFadeValue(fadeAmount);\n\n        // Resolve the promsie once we've finished.\n        return fadeAmount \u003e= 1f;\n    });\n}\n```\n\n### PromiseTimer.WaitWhile\n\nWaitWhile is exactly the same as WaitUntil except that it resolves when its predicate function returns false. Think of WaitUntil as running *until* its predicate returns true, and WaitWhile as running *while* its predicate returns true, stopping when it is false.\n\n### TimeData struct\n\nTimeData is passed to you as a paramter when using either PromiseTimer.WaitUntil or PromiseTimer.WaitWhile. It contains the following public fields:\n\n- elapsedTime\n    - The amount of time that has elapsed since the pending promise started running\n- deltaTime\n    - The amount of time since the last time the pending promise was updated.\n- elapsedUpdates\n    - The amount of times that PromiseTimer.Update() has been called since the pending promise started running\n\n## Examples\n\n\n- Example1\n    - Example of downloading text from a URL using a promise.\n- Example2\n    - Example of a promise that is rejected because of an error during\n    - the async operation.\n- Example3\n    - This example downloads search results from google then transforms the result to extract links.\n    - Includes both error handling and a completion handler.\n- Example4\n    - This example downloads search results from google, extracts the links and follows only a single first link, downloads its then prints the result.\n    - Includes both error handling and a completion handler.\n- Example5\n    - This example downloads search results from google, extracts the links, follows all (absolute) links and combines all async operations in a single operation using the `All` function.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FReal-Serious-Games%2FC-Sharp-Promise","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FReal-Serious-Games%2FC-Sharp-Promise","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FReal-Serious-Games%2FC-Sharp-Promise/lists"}