{"id":1097,"url":"https://github.com/vadymmarkov/When","last_synced_at":"2025-08-06T13:32:30.429Z","repository":{"id":56927507,"uuid":"51870779","full_name":"vadymmarkov/When","owner":"vadymmarkov","description":":alarm_clock: A lightweight implementation of Promises in Swift","archived":false,"fork":false,"pushed_at":"2020-03-30T16:50:29.000Z","size":428,"stargazers_count":266,"open_issues_count":2,"forks_count":35,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-12-07T19:50:36.472Z","etag":null,"topics":["promise","swift"],"latest_commit_sha":null,"homepage":"https://github.com/vadymmarkov","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vadymmarkov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-16T21:16:05.000Z","updated_at":"2024-10-29T16:30:07.000Z","dependencies_parsed_at":"2022-08-20T23:30:35.306Z","dependency_job_id":null,"html_url":"https://github.com/vadymmarkov/When","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadymmarkov%2FWhen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadymmarkov%2FWhen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadymmarkov%2FWhen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadymmarkov%2FWhen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vadymmarkov","download_url":"https://codeload.github.com/vadymmarkov/When/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228905476,"owners_count":17989773,"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":["promise","swift"],"created_at":"2024-01-05T20:15:38.852Z","updated_at":"2024-12-09T14:30:53.530Z","avatar_url":"https://github.com/vadymmarkov.png","language":"Swift","funding_links":[],"categories":["EventBus","Libs","Events [🔝](#readme)"],"sub_categories":["Getting Started","Events","Other free courses","Linter"],"readme":"![When](https://github.com/vadymmarkov/When/blob/master/Resources/WhenPresentation.png)\n\n[![CI Status](http://img.shields.io/travis/vadymmarkov/When.svg?style=flat)](https://travis-ci.org/vadymmarkov/When)\n[![Version](https://img.shields.io/cocoapods/v/When.svg?style=flat)](http://cocoadocs.org/docsets/When)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![License](https://img.shields.io/cocoapods/l/When.svg?style=flat)](http://cocoadocs.org/docsets/When)\n[![Platform](https://img.shields.io/cocoapods/p/When.svg?style=flat)](http://cocoadocs.org/docsets/When)\n\n## Description\n\n**When** is a lightweight implementation of [Promises](https://en.wikipedia.org/wiki/Futures_and_promises)\nin Swift. It doesn't include any helper functions for iOS and OSX and it's\nintentional, to remove redundant complexity and give you more freedom and\nflexibility in your choices. It is type safe, thanks Swift generics, so you\ncould create ***promises*** with whatever type you want.\n\n**When** can easily be integrated into your projects and libraries to move your\nasynchronous code up to the next level.\n\n## Table of Contents\n\n\u003cimg src=\"https://github.com/vadymmarkov/When/blob/master/Resources/WhenIcon.png\" alt=\"When Icon\" width=\"190\" height=\"190\" align=\"right\" /\u003e\n\n* [Why?](#why)\n* [Usage](#usage)\n  * [Promise](#promise)\n  * [Done](#done)\n  * [Fail](#fail)\n  * [Always](#always)\n  * [Then](#then)\n  * [Recover](#recover)\n  * [When](#when)\n* [Reactive extensions](#reactive-extensions)\n* [Installation](#installation)\n* [Author](#author)\n* [Credits](#credits)\n* [Contributing](#contributing)\n* [License](#license)\n\n## Why?\n\nTo make asynchronous code more readable and standardized:\n\n```swift\nfetchJSON().then({ data: NSData -\u003e [[String: AnyObject]] in\n  // Convert to JSON\n  return json\n}).then({ json: [[String: AnyObject]] -\u003e [Entity] in\n  // Map JSON\n  // Save to database\n  return items\n}).done({ items: [Entity] in\n  self.items = items\n  self.tableView.reloadData()\n}).error({ error in\n  print(error)\n})\n```\n\n## Usage\n\n### Promise\nA ***promise*** represents the future value of a task. Promises start in a pending\nstate and then could be resolved with a value or rejected with an error.\n\n```swift\n// Creates a new promise that could be resolved with a String value\nlet promise = Promise\u003cString\u003e()\n// Resolves the promise\npromise.resolve(\"String\")\n// Or rejects the promise\npromise.reject(Error.notFound)\n```\n\n```swift\n// Creates a new promise that is resolved with a String value\nlet promise = Promise({\n  return \"String\"\n})\n```\n\n```swift\n// Creates a new promise that is rejected with an Error\nlet promise = Promise({\n  //...\n  throw Error.notFound\n})\n```\n\nCallbacks of the current ***promise*** and all the chained promises\n(created with [then](#then)) are executed on the main queue by default, but\nyou can always specify the needed queue in `init`:\n\n```swift\nlet promise = Promise\u003cString\u003e(queue: dispatch_get_main_queue())\n```\n\n### Done\nAdds a handler to be called when the ***promise*** object is resolved with a value:\n\n```swift\n// Create a new promise in a pending state\nlet promise = Promise\u003cString\u003e()\n// Add done callback\npromise.done({ value in\n  print(value)\n})\n// Resolve the promise\npromise.resolve(\"String\")\n```\n\n### Fail\nAdds a handler to be called when the ***promise*** object is rejected with\nan `Error`:\n\n```swift\n// Create a new promise in a pending state\nlet promise = Promise\u003cString\u003e()\n// Add fail callback\npromise.fail({ error in\n  print(error)\n})\n// Reject the promise\npromise.reject(Error.notFound)\n```\n\nIt's also possible to cancel a promise, which means it will be rejected with\n`PromiseError.cancelled` error. `FailurePolicy` can be used if you want to\nignore this error in your `fail` handler:\n\n```swift\n// Create a new promise in a pending state\nlet promise = Promise\u003cString\u003e()\n// This callback will not be called when a promise is cancelled\npromise.fail({ error in\n  print(error)\n})\n// This callback will be called when a promise is cancelled\npromise.fail(policy: .allErrors, { error in\n  print(error)\n})\n// Cancel the promise\npromise.cancel()\n```\n\n### Always\nAdds a handler to be called when the ***promise*** object is either resolved or\nrejected. This callback will be called after [done](#done) or [fail](#fail)\nhandlers.\n\n```swift\n// Create a new promise in a pending state\nlet promise = Promise\u003cString\u003e()\n// Add always callback\npromise.always({ result in\n  switch result {\n  case let .success(value):\n    print(value)\n  case let .failure(error):\n    print(error)\n  }\n})\n// Resolve or reject the promise\npromise.resolve(\"String\") // promise.reject(Error.notFound)\n```\n\n### Then\nReturns a new ***promise*** that can use the result value of the current\npromise. It means that you could easily create chains of ***promises*** to\nsimplify complex asynchronous operations into clear and simple to understand\nlogic.\n\nA new ***promise*** is resolved with the value returned from the provided\nclosure:\n\n```swift\nlet promise = Promise\u003cNSData\u003e()\n\npromise\n  .then({ data -\u003e Int in\n    return data.length\n  }).then({ length -\u003e Bool in\n    return length \u003e 5\n  }).done({ value in\n    print(value)\n  })\n\npromise.resolve(\"String\".dataUsingEncoding(NSUTF8StringEncoding)!)\n```\n\nA new ***promise*** is resolved when the ***promise*** returned from the\nprovided closure resolves:\n```swift\nstruct Networking {\n  static func GET(url: NSURL) -\u003e Promise\u003cNSData\u003e {\n    let promise = Promise\u003cNSData\u003e()\n    //...\n    return promise\n  }\n}\n\nNetworking.GET(url1)\n  .then({ data -\u003e Promise\u003cNSData\u003e in\n    //...\n    return Networking.GET(url2)\n  }).then({ data -\u003e Int in\n    return data.length\n  }).done({ value in\n    print(value)\n  })\n```\n\n***then*** closure is executed on the main queue by default, but you can pass a\nneeded queue as a parameter:\n\n```swift\npromise.then(on: dispatch_get_global_queue(QOS_CLASS_UTILITY, 0))({ data -\u003e Int in\n  //...\n})\n```\n\nIf you want to use background queue there are the helper methods for this case:\n\n```swift\npromise1.thenInBackground({ data -\u003e Int in\n  //...\n})\n\npromise2.thenInBackground({ data -\u003e Promise\u003cNSData\u003e in\n  //...\n})\n```\n\n### Recover\nReturns a new ***promise*** that can be used to continue the chain when an\nerror was thrown.\n\n```swift\nlet promise = Promise\u003cString\u003e()\n// Recover the chain\npromise\n  .recover({ error -\u003e Promise\u003cString\u003e in\n    return Promise({\n      return \"Recovered\"\n    })\n  })\n  .done({ string in\n    print(string) // Recovered\n  })\n// Reject the promise\npromise.reject(Error.notFound)\n```\n\n### When\nProvides a way to execute callback functions based on one or more\n***promises***. The ***when*** method returns a new \"master\" ***promise*** that\ntracks the aggregate state of all the passed ***promises***. The method will\nresolve its \"master\" ***promise*** as soon as all the ***promises*** resolve,\nor reject the \"master\" ***promise*** as soon as one of the ***promises*** is\nrejected. If the \"master\" ***promise*** is resolved, the ***done*** callback is\nexecuted with resolved values for each of the ***promises***:\n\n```swift\nlet promise1 = Promise\u003cInt\u003e()\nlet promise2 = Promise\u003cString\u003e()\nlet promise3 = Promise\u003cInt\u003e()\n\nwhen(promise1, promise2, promise3)\n  .done({ value1, value2, value3 in\n    print(value1)\n    print(value2)\n    print(value3)\n  })\n\npromise1.resolve(1)\npromise2.resolve(\"String\")\npromise3.resolve(3)\n```\n\n## Reactive extensions\n\nUse the following extension in order to integrate **When** with [RxSwift](https://github.com/ReactiveX/RxSwift):\n\n```swift\nimport RxSwift\n\nextension Promise: ObservableConvertibleType {\n  public func asObservable() -\u003e Observable\u003cT\u003e {\n    return Observable.create({ observer in\n      self\n        .done({ value in\n          observer.onNext(value)\n        })\n        .fail({ error in\n          observer.onError(error)\n        })\n        .always({ _ in\n          observer.onCompleted()\n        })\n\n      return Disposables.create()\n    })\n  }\n}\n```\n\n## Installation\n\n**When** is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'When'\n```\n\nFor `RxSwift` extensions you can use CocoaPods subspecs:\n\n```ruby\npod 'When/RxSwift'\n```\n\n**When** is also available through [Carthage](https://github.com/Carthage/Carthage).\nTo install just write into your Cartfile:\n\n```ruby\ngithub \"vadymmarkov/When\"\n```\n\n## Author\n\nVadym Markov, markov.vadym@gmail.com\n\n## Credits\n\nCredits for inspiration go to [PromiseKit](https://github.com/mxcl/PromiseKit)\nand [Then](https://github.com/onmyway133/Then).\n\n## Contributing\n\nCheck the [CONTRIBUTING](https://github.com/vadymmarkov/When/blob/master/CONTRIBUTING.md) file for more info.\n\n## License\n\n**When** is available under the MIT license. See the [LICENSE](https://github.com/vadymmarkov/When/blob/master/LICENSE.md) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadymmarkov%2FWhen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvadymmarkov%2FWhen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadymmarkov%2FWhen/lists"}