{"id":1108,"url":"https://github.com/albertodebortoli/Promis","last_synced_at":"2025-07-30T20:31:21.433Z","repository":{"id":25953135,"uuid":"106967668","full_name":"albertodebortoli/Promis","owner":"albertodebortoli","description":"The easiest Future and Promises framework in Swift. No magic. No boilerplate.","archived":false,"fork":false,"pushed_at":"2023-03-17T05:53:19.000Z","size":142,"stargazers_count":108,"open_issues_count":2,"forks_count":6,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-05-28T16:26:18.947Z","etag":null,"topics":["futures","generics","promises","swift"],"latest_commit_sha":null,"homepage":"http://albertodebortoli.com","language":"Swift","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/albertodebortoli.png","metadata":{"files":{"readme":"README.md","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,"governance":null}},"created_at":"2017-10-14T22:35:05.000Z","updated_at":"2024-04-22T13:39:22.000Z","dependencies_parsed_at":"2023-10-20T16:30:47.314Z","dependency_job_id":null,"html_url":"https://github.com/albertodebortoli/Promis","commit_stats":{"total_commits":73,"total_committers":3,"mean_commits":"24.333333333333332","dds":0.04109589041095896,"last_synced_commit":"cbc7accb649990c1248cf1de7159cf427a932550"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertodebortoli%2FPromis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertodebortoli%2FPromis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertodebortoli%2FPromis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertodebortoli%2FPromis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/albertodebortoli","download_url":"https://codeload.github.com/albertodebortoli/Promis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":215182685,"owners_count":15840918,"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":["futures","generics","promises","swift"],"created_at":"2024-01-05T20:15:39.089Z","updated_at":"2024-08-13T13:30:36.778Z","avatar_url":"https://github.com/albertodebortoli.png","language":"Swift","funding_links":[],"categories":["EventBus"],"sub_categories":["Getting Started","Other free courses","Linter"],"readme":"# Promis\n\n[![Build Status](https://travis-ci.org/albertodebortoli/Promis.svg?branch=master)](https://travis-ci.org/albertodebortoli/Promis)\n[![Version](https://img.shields.io/cocoapods/v/Promis.svg?style=flat)](http://cocoapods.org/pods/Promis)\n[![License](https://img.shields.io/cocoapods/l/Promis.svg?style=flat)](http://cocoapods.org/pods/Promis)\n[![Platform](https://img.shields.io/cocoapods/p/Promis.svg?style=flat)](http://cocoapods.org/pods/Promis)\n\nThe easiest Future and Promises framework in Swift. No magic. No boilerplate.\n\n## Overview\n\nWhile starting from the Objective-C implementation of [JustPromises](https://github.com/justeat/JustPromises) and keeping the code minimalistic, this library adds the following:\n\n- conversion to Swift 4\n- usage of generics to allow great type inference that wasn't possible in Objective-C\n- overall refactoring for fresh and modern code\n- remove the unnecessary and misleading concept of Progress causing bad patterns to emerge\n\nYou can read about the theory behind Future and Promises on [Wikipedia](https://en.wikipedia.org/wiki/Futures_and_promises), here are the main things you should know to get started.\n\n- Promises represent the promise that a task will be fulfilled in the future while the future holds the state of such resolution.\n- Futures, when created are in the unresolved state and can be resolved with one of 3 states: with a result, an error, or being cancelled.\n- Futures can be chained, allowing to avoid the [pyramid of doom](https://twitter.com/piscis168/status/641237956070666240) problem, clean up asynchronous code paths and simplify error handling.\n\nPromis brags about being/having:\n\n- Fully unit-tested and documented 💯\n- Thread-safe 🚦\n- Clean interface 👼\n- Support for chaining ⛓\n- Support for cancellation 🙅‍♂️\n- Queue-based block execution if needed 🚆\n- Result type provided via generics 🚀\n- Keeping the magic to the minimum, leaving the code in a readable state without going off of a tangent with fancy and unnecessary design decisions ಠ_ಠ\n\n## Alternatives\n\nOther open-source solutions exist such as:\n- [FutureKit](https://github.com/FutureKit/FutureKit)\n- [PromiseKit](https://github.com/mxcl/PromiseKit)\n- [JustPromises](https://github.com/justeat/JustPromises)\n- [Promises](https://github.com/google/promises)\n\nPromis takes inspiration from the Objective-C version of JustPromises developed by the iOS Team of [Just Eat](https://www.just-eat.com/) which is really concise and minimalistic, while other libraries are more weighty.\n\n## Usage\n\nThe following example should outline the main benefits of using futures via chaining.\n\n```swift\nlet request = URLRequest(url: URL(string: \"http://example.com\")!)\n\n// starts by hitting an API to download data\ngetData(request: request).thenWithResult { data in\n    // continue by parsing the retrieved data\n    parse(data: data)\n}.thenWithResult { parsedData in\n    // continue by mapping the parsed data\n    map(data: parsedData)\n}.onError { error in\n    // executed only in case an error occurred in the chain\n    print(\"error: \" + String(describing: error))\n}.finally(queue: .main) { future in\n    // always executed, no matter the state of the previous future or how the chain did perform\n    switch future.state {\n        case .result(let value):\n            print(String(describing: value))\n        case .error(let err):\n            print(String(describing: err))\n        case .cancelled:\n            print(\"future is in a cancelled state\")\n        case .unresolved:\n            print(\"this really cannot be if any chaining block is executed\")\n        }\n}\n```\n\nThe functions used in the example have the following signatures:\n\n```swift\nfunc getData(request: URLRequest) -\u003e Future\u003cData\u003e\nfunc parse(data: Data) -\u003e Future\u003c[Dictionary\u003cString,AnyObject\u003e]\u003e\nfunc map(data: [Dictionary\u003cString,AnyObject\u003e]) -\u003e Future\u003c[FooBar]\u003e\n```\n\nPromises and Futures are parametrized leveraging the power of the generics, meaning that Swift can infer the type of the result compile type. This was a considerable limitation in the Objective-C world and we can now prevent lots of issues at build time thanks to the static typing nature of the language. The state of the future is an enum defined as follows:\n\n```swift\nenum FutureState\u003cResultType\u003e {\n    case unresolved\n    case result(ResultType)\n    case error(Error)\n    case cancelled\n}\n```\n\nPromises are created and resolved like so:\n\n```swift\nlet promise = Promise\u003cResultType\u003e()\npromise.setResult(value)\n// or\npromise.setError(error)\n// or\npromise.cancel()\n```\n\nContinuation methods used for chaining are the following:\n\n```swift\nfunc then\u003cNextResultType\u003e(queue: DispatchQueue? = nil, task: @escaping (Future) -\u003e Future\u003cNextResultType\u003e) -\u003e Future\u003cNextResultType\u003e\nfunc thenWithResult\u003cNextResultType\u003e(queue: DispatchQueue? = nil, continuation: @escaping (ResultType) -\u003e Future\u003cNextResultType\u003e) -\u003e Future\u003cNextResultType\u003e {\nfunc onError(queue: DispatchQueue? = nil, continuation: @escaping (Error) -\u003e Void) -\u003e Future {\nfunc finally(queue: DispatchQueue? = nil, block: @escaping (Future\u003cResultType\u003e) -\u003e Void)\n```\n\nAll the functions can accept an optional `DispatchQueue` used to perform the continuation blocks.\n\n\n### Best practices\n\nFunctions wrapping async tasks should follow the below pattern:\n\n```swift\nfunc wrappedAsyncTask() -\u003e Future\u003cResultType\u003e {\n\n    let promise = Promise\u003cData\u003e()\n    someAsyncOperation() { data, error in\n        // resolve the promise according to how the async operations did go\n        switch (data, error) {\n        case (let data?, _):\n            promise.setResult(data)\n        case (nil, let error?):\n            promise.setError(error)\n        // etc.\n        }\n    }\n    return promise.future\n}\n```\n\nYou could chain an `onError` continuation before returning the future to allow in-line error handling, which I find to be a very handy pattern.\n\n```swift\n// ...\nreturn promise.future.onError {error in\n    // handle/log error\n}\n```\n\n### Pitfalls\n\nWhen using `then` or `thenWithResult`, the following should be taken in consideration.\n\n```swift\n...}.thenWithResult { data -\u003e Future\u003cNextResultType\u003e in\n    /**\n    If a block is not trivial, Swift cannot infer the type of the closure and gives the error\n    'Unable to infer complex closure return type; add explicit type to disambiguate'\n    so you'll have to add `-\u003e Future\u003cNextResultType\u003e to the block signature\n    \n    You can make the closure complex just by adding any extra statement (like a print).\n    \n    All the more reason to structure your code as done in the first given example :)\n    */\n    print(\"complex closure\")\n    return parse(data: data)\n}\n```\n\nPlease check the GettingStarted playground in the demo app to see the complete implementation of the above examples.\n\n## Installation\n\n### CocoaPods\n\nAdd `Promis` to your Podfile\n\n```ruby\nuse_frameworks!\ntarget 'MyTarget' do\n    pod 'Promis', '~\u003e x.y.z'\nend\n```\n\n```bash\n$ pod install\n```\n\n### Carthage\n\n```ruby\ngithub \"albertodebortoli/Promis\" ~\u003e \"x.y.z\"\n```\n\nThen on your application target *Build Phases* settings tab, add a \"New Run Script Phase\". Create a Run Script with the following content:\n\n```ruby\n/usr/local/bin/carthage copy-frameworks\n```\n\nand add the following paths under \"Input Files\":\n\n```ruby\n$(SRCROOT)/Carthage/Build/iOS/Promis.framework\n```\n\n## Author\n\nAlberto De Bortoli \u003calbertodebortoli.website@gmail.com\u003e\nTwitter: [@albertodebo](https://twitter.com/albertodebo)\nGitHub: [albertodebortoli](https://github.com/albertodebortoli)\nwebsite: [albertodebortoli.com](http://albertodebortoli.com)\n\n## License\n\nPromis is available under the Apache 2 license in respect of JustPromises which this library takes inspiration from. See the [LICENSE](LICENSE) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertodebortoli%2FPromis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falbertodebortoli%2FPromis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertodebortoli%2FPromis/lists"}