All Projects → AsyncNinja → Asyncninja

AsyncNinja / Asyncninja

Licence: mit
A complete set of primitives for concurrency and reactive programming on Swift

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Asyncninja

Redux Most
Most.js based middleware for Redux. Handle async actions with monadic streams & reactive programming.
Stars: ✭ 137 (-6.16%)
Mutual labels:  async, reactive, functional
Bulb
A reactive programming library for JavaScript.
Stars: ✭ 84 (-42.47%)
Mutual labels:  reactive, functional
Suave
Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition.
Stars: ✭ 1,196 (+719.18%)
Mutual labels:  async, functional
Drone
CLI utility for Drone, an Embedded Operating System.
Stars: ✭ 114 (-21.92%)
Mutual labels:  async, concurrency
Portable concurrency
Portable implementation of future/promise API in C++
Stars: ✭ 48 (-67.12%)
Mutual labels:  concurrency, future
Ea Async
EA Async implements async-await methods in the JVM.
Stars: ✭ 1,085 (+643.15%)
Mutual labels:  async, concurrency
Motorcyclejs
A statically-typed, functional and reactive framework for modern browsers
Stars: ✭ 107 (-26.71%)
Mutual labels:  reactive, functional
Jdonframework
Domain-Driven-Design Pub/Sub Domain-Events framework
Stars: ✭ 978 (+569.86%)
Mutual labels:  reactive, concurrency
Effector React Realworld Example App
Exemplary real world application built with Effector + React
Stars: ✭ 119 (-18.49%)
Mutual labels:  reactive, functional
Vertx Auth
Stars: ✭ 122 (-16.44%)
Mutual labels:  async, reactive
Typed
The TypeScript Standard Library
Stars: ✭ 124 (-15.07%)
Mutual labels:  future, functional
Vibe.d
Official vibe.d development
Stars: ✭ 1,043 (+614.38%)
Mutual labels:  async, concurrency
Phobos
The standard library of the D programming language
Stars: ✭ 1,038 (+610.96%)
Mutual labels:  concurrency, functional
Async
Async utilities for Golang.
Stars: ✭ 72 (-50.68%)
Mutual labels:  async, concurrency
Inferno Most Fp Demo
A demo for the ReactJS Tampa Bay meetup showing how to build a React+Redux-like architecture from scratch using Inferno, Most.js, reactive programmning, and various functional programming tools & techniques
Stars: ✭ 45 (-69.18%)
Mutual labels:  reactive, functional
Swimmer
🏊 Swimmer - An async task pooling and throttling utility for JS
Stars: ✭ 94 (-35.62%)
Mutual labels:  async, concurrency
Orleans
Orleans is a cross-platform framework for building distributed applications with .NET
Stars: ✭ 8,131 (+5469.18%)
Mutual labels:  reactive, concurrency
Rxjava Android Samples
Learning RxJava for Android by example
Stars: ✭ 7,520 (+5050.68%)
Mutual labels:  reactive, concurrency
Advanced Vertx Guide
A gentle guide for advanced Vert.x users
Stars: ✭ 118 (-19.18%)
Mutual labels:  async, reactive
Unityfx.async
Asynchronous operations (promises) for Unity3d.
Stars: ✭ 143 (-2.05%)
Mutual labels:  async, future

AsyncNinja Title

A complete set of primitives for concurrency and reactive programming on Swift

Gitter CocoaPods Carthage compatible Build Status

  • 1.4.0 is the latest and greatest, but only for Swift 4.2 and 5.0
  • use 1.3.0 is for Swift 4.0+
  • use 1.2.4 for latest release for Swift 3
Features
🦄
powerful primitives
Future, Promise, Channel, Producer, Sink, Cache, ...
🤘
versatile transformations
map, filter, recover, debounce, distinct, ...
✌️
convenient combination
flatMap, merge, zip, sample, scan, reduce, ...
🙌
improves existing things
Key-Value Observing, target-action, notifications, bindings
🍳
less boilerplate code
neat cancellation, threading, memory manament
🕶
extendable
powerful extensions for URLSession, UI controls, CoreData, ...
🍱
all platforms
🖥 macOS 10.10+ 📱 iOS 8.0+ 📺 tvOS 9.0+ ⌚️ watchOS 2.0+ 🐧 Linux
🤓
documentation
100% + sample code, see full documentation
🔩
simple integration
SPM, CocoaPods, Carthage

Communication

Reactive Programming

reactive properties

let searchResults = searchBar.rp.text
  .debounce(interval: 0.3)
  .distinct()
  .flatMap(behavior: .keepLatestTransform) { (query) -> Future<[SearchResult]> in
    return query.isEmpty
      ? .just([])
      : searchGitHub(query: query).recover([])
  }

bindings

  • unbinds automatically
  • dispatches to a correct queue automatically
  • no .observeOn(MainScheduler.instance) and .disposed(by: disposeBag)
class MyViewController: UIViewController {
  /* ... */
  @IBOutlet weak var myLabel: UILabel!

  override func viewDidLoad() {
    super.viewDidLoad()
    UIDevice.current.rp.orientation
      .map { $0.description }
      .bind(myLabel.rp.text)
  }
  
  /* ... */
}

contexts usage

  • no [weak self]
  • no DispatchQueue.main.async { ... }
  • no .observeOn(MainScheduler.instance)
class MyViewController: NSViewController {
  let service: MyService

  /* ... */
  
  func fetchAndPresentItems(for request: Request) {
    service.perform(request: request)
      .map(context: self, executor: .primary) { (self, response) in
        return self.items(from: response)
      }
      .onSuccess(context: self) { (self, items) in
        self.present(items: items)
      }
      .onFailure(context: self) { (self, error) in
        self.present(error: error)
      }
  }
  
  func items(from response: Response) throws -> [Items] {
    /* ... extract items from response ... */
  }
  
  func present(items: [Items]) {
    /* ... update UI ... */
  }
}

class MyService {
  func perform(request: Request) -> Future<Response> {
    /* ... */
  }
}

In Depth

Let's assume that we have:

  • Person is an example of a struct that contains information about the person.
  • MyService is an example of a class that serves as an entry point to the model. Works in a background.
  • MyViewController is an example of a class that manages UI-related instances. Works on the main queue.

Code on callbacks

extension MyViewController {
  func present(personWithID identifier: String) {
    myService.fetch(personWithID: identifier) {
      (person, error) in

      /* do not forget to dispatch to the main queue */
      DispatchQueue.main.async {

        /* do not forget the [weak self] */
        [weak self] in
        guard let strongSelf = self
          else { return }

        if let person = person {
          strongSelf.present(person: person)
        } else if let error = error {
          strongSelf.present(error: error)
        } else {
          fatalError("There is neither person nor error. What has happened to this world?")
        }
      }
    }
  }
}

extension MyService {
  func fetch(personWithID: String, callback: @escaping (Person?, Error?) -> Void) {
    /* ... */
  }
}
  • "do not forget" comment x2
  • the block will be retained and called even if MyViewController was already deallocated

Code with other libraries that provide futures

extension MyViewController {
  func present(personWithID identifier: String) {
    myService.fetch(personWithID: identifier)

      /* do not forget to dispatch to the main queue */
      .onComplete(executor: .main) {

        /* do not forget the [weak self] */
        [weak self] (completion) in
        if let strongSelf = self {
          completion.onSuccess(strongSelf.present(person:))
          completion.onFailure(strongSelf.present(error:))
        }
      }
  }
}

extension MyService {
  func fetch(personWithID: String) -> Future<Person> {
    /* ... */
  }
}
  • "do not forget" comment x2
  • the block will be retained and called even if MyViewController was already deallocated

Code with AsyncNinja

extension MyViewController {
  func present(personWithID identifier: String) {
    myService.fetch(personWithID: identifier)
      .onSuccess(context: self) { (self, person) in
        self.present(person: person)
      }
      .onFailure(context: self) { (self, error) in
        self.present(error: error)
      }
  }
}

extension MyService {
  func fetch(personWithID: String) -> Future<Person> {
    /* ... */
  }
}

Using Futures

Let's assume that we have function that finds all prime numbers lesser than n

func primeNumbers(to n: Int) -> [Int] { /* ... */ }

Making future

let futurePrimeNumbers: Future<[Int]> = future { primeNumbers(to: 10_000_000) }

Applying transformation

let futureSquaredPrimeNumbers = futurePrimeNumbers
  .map { (primeNumbers) -> [Int] in
    return primeNumbers.map { (number) -> Int
      return number * number
    }
  }

Synchronously waiting for completion

if let fallibleNumbers = futurePrimeNumbers.wait(seconds: 1.0) {
  print("Number of prime numbers is \(fallibleNumbers.success?.count)")
} else {
  print("Did not calculate prime numbers yet")
}

Subscribing for completion

futurePrimeNumbers.onComplete { (falliblePrimeNumbers) in
  print("Number of prime numbers is \(falliblePrimeNumbers.success?.count)")
}

Combining futures

let futureA: Future<A> = /* ... */
let futureB: Future<B> = /* ... */
let futureC: Future<C> = /* ... */
let futureABC: Future<(A, B, C)> = zip(futureA, futureB, futureC)

Transition from callbacks-based flow to futures-based flow:

class MyService {
  /* implementation */
  
  func fetchPerson(withID personID: Person.Identifier) -> Future<Person> {
    let promise = Promise<Person>()
    self.fetchPerson(withID: personID, callback: promise.complete)
    return promise
  }
}

Transition from futures-based flow to callbacks-based flow

class MyService {
  /* implementation */
  
  func fetchPerson(withID personID: Person.Identifier,
                   callback: @escaping (Fallible<Person>) -> Void) {
    self.fetchPerson(withID: personID)
      .onComplete(callback)
  }
}

Using Channels

Let's assume we have function that returns channel of prime numbers: sends prime numbers as finds them and sends number of found numbers as completion

func makeChannelOfPrimeNumbers(to n: Int) -> Channel<Int, Int> { /* ... */ }

Applying transformation

let channelOfSquaredPrimeNumbers = channelOfPrimeNumbers
  .map { (number) -> Int in
      return number * number
    }

Synchronously iterating over update values.

for number in channelOfPrimeNumbers {
  print(number)
}

Synchronously waiting for completion

if let fallibleNumberOfPrimes = channelOfPrimeNumbers.wait(seconds: 1.0) {
  print("Number of prime numbers is \(fallibleNumberOfPrimes.success)")
} else {
  print("Did not calculate prime numbers yet")
}

Synchronously waiting for completion #2

let (primeNumbers, numberOfPrimeNumbers) = channelOfPrimeNumbers.waitForAll()

Subscribing for update

channelOfPrimeNumbers.onUpdate { print("Update: \($0)") }

Subscribing for completion

channelOfPrimeNumbers.onComplete { print("Completed: \($0)") }

Making Channel

func makeChannelOfPrimeNumbers(to n: Int) -> Channel<Int, Int> {
  return channel { (update) -> Int in
    var numberOfPrimeNumbers = 0
    var isPrime = Array(repeating: true, count: n)

    for number in 2..<n where isPrime[number] {
      numberOfPrimeNumbers += 1
      update(number)

      // updating seive
      var seiveNumber = number + number
      while seiveNumber < n {
        isPrime[seiveNumber] = false
        seiveNumber += number
      }
    }

    return numberOfPrimeNumbers
  }
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].