Advertisement
Guest User

Untitled

a guest
May 21st, 2019
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import ExecutionContext from "../async/ExecutionContext";
  2. import {None, Option, Some} from "../monads/Option";
  3. import Try from "../monads/Try";
  4.  
  5. /**
  6.  * This class is a super simplified implementation of Scala futures. This difference lies in the
  7.  * fact that since implicit context is not used here, the chain of futures must be run explicitly
  8.  * through the run method. For the same reason, all void combinators, like onSuccess, return the
  9.  * type Future <T>. In practice, it looks like this:
  10.  *
  11.  * {{{
  12.  *   new Future<number>(() => {
  13.  *       console.log("calc");
  14.  *       return 99;
  15.  *   }, executor)
  16.  *      .map((v) => {
  17.  *          return v + 100;
  18.  *      })
  19.  *      .onFailed((e) => {
  20.  *         console.log(`Error = ${e.message}`)
  21.  *      })
  22.  *      .onSuccess((v) => {
  23.  *         console.log(`Result = ${v}`)
  24.  *      })
  25.  *      .run();
  26.  * }}}
  27.  *
  28.  * Also this class implements the functionality of promise. In order to create a promise, you need to make
  29.  * a call to Future.Promise (). This call will return an unfired future that behaves just like a normal one,
  30.  * but must run by the method success or failed. The principle of operation of these methods is identical for
  31.  * all types of promise. Example:
  32.  *
  33.  * {{{
  34.  *     let p = Future.Promise<number>(executor)
  35.  *      .map((v) => {
  36.  *         return v + 100;
  37.  *      })
  38.  *      .onSuccess((v: number) => {
  39.  *          console.log(`Result = ${v}`)
  40.  *      })
  41.  *      .onFailed((e) => {
  42.  *          console.log(`Error = ${e.message}`)
  43.  *      });
  44.  *
  45.  *     console.log("Some before execution code...");
  46.  *     p.success(99);
  47.  * }}}
  48.  *
  49.  */
  50. export default class Future<T> {
  51.  
  52.     /** Next operation after complete the computation. This value contain function, witch call running the
  53.      * next chained future */
  54.     next: () => void = null;
  55.  
  56.     /** Parent of the future. Root future has no parent */
  57.     parent: Future<any> = null;
  58.  
  59.     /** Chain executor */
  60.     executor: ExecutionContext;
  61.  
  62.     /** Function with computation. For root future this is an app code function presented in constructor.
  63.      *  Fot any other chained future this value contains a wrapper derived be the combinator functions witch
  64.      *  apply to the result of the previous future computations */
  65.     f: () => T = null;
  66.  
  67.     /** Computation result */
  68.     value: Option<Try<T>> = new None();
  69.  
  70.     /** Create new future
  71.      *
  72.      * @param {() => T} f function for asynchronous execution
  73.      * @param {ExecutionContext} executor execution context
  74.      */
  75.     constructor (f: () => T, executor: ExecutionContext) {
  76.         this.executor = executor;
  77.         this.f = f;
  78.     }
  79.  
  80.     /** Create already completed future
  81.      *
  82.      * @param {T} value value for completion
  83.      * @param {ExecutionContext} executor  execution context
  84.      * @return {Future<T>} completed future
  85.      */
  86.     static Successful<T>(value: T, executor: ExecutionContext): Future<T> {
  87.         let fut = new Future<T>(null, executor);
  88.         fut.value = new Some(Try.doWork(() => value));
  89.         return fut;
  90.     }
  91.  
  92.     /** Create new future as promise. This type of future does not perform calculations on its own.
  93.      *  She expects that they will be presented to her from the outside. The run method is not used
  94.      *  to start the futures. Instead, there are special methods, success and failed. Through them
  95.      *  and provides the result of filling the promise.
  96.      *
  97.      * @param {ExecutionContext} executor
  98.      * @return {Future<T>}
  99.      * @constructor
  100.      */
  101.     static Promise<T>(executor: ExecutionContext): Future<T> {
  102.         let fut = new Future<T>(null, executor);
  103.         fut.f = () => {
  104.             if (fut.value.get().isSuccess()) {
  105.                 return fut.value.get().get();
  106.             } else {
  107.                 throw fut.value.get().failed().get();
  108.             }
  109.         };
  110.  
  111.         return fut;
  112.     }
  113.  
  114.     /** Run futures chain for execution
  115.      *
  116.      * @return {Future<T>} final future in the chain
  117.      */
  118.     run(): Future<T> {
  119.         this.execRoot();
  120.         return this;
  121.     }
  122.  
  123.     /** Present result to the promise
  124.      *
  125.      * @param value result
  126.      */
  127.     success(value: any) {
  128.         this.execRootPromise(Try.doWork(() => value))
  129.     }
  130.  
  131.     /** Fail promise with error
  132.      *
  133.      * @param {Error} error exception for failing
  134.      */
  135.     failed(error: Error) {
  136.         this.execRootPromise(Try.doWork(() => { throw error }))
  137.     }
  138.  
  139.     map<S>(f: (T) => S): Future<S> {
  140.         let from = this;
  141.         let fut = new Future<S>(null, this.executor);
  142.         fut.parent = this;
  143.         this.next = () => {
  144.             if (from.value.get().isSuccess()) {
  145.                 fut.value = new Some(Try.doWork(() => f(from.value.get().get())));
  146.             } else {
  147.                 fut.value = new Some(Try.doWork(() => {
  148.                     throw from.value.get().failed().get();
  149.                 }));
  150.             }
  151.  
  152.             fut.flatRun();
  153.         };
  154.         return fut;
  155.     }
  156.  
  157.     onSuccess<S>(f: (T) => S): Future<S> {
  158.         let from = this;
  159.         let fut = new Future<S>(() => {
  160.             return f(from.value.get());
  161.         }, this.executor);
  162.         fut.parent = this;
  163.         this.next = () => {
  164.             if (from.value.get().isSuccess()) {
  165.                 fut.value = new Some(Try.doWork(() => f(from.value.get().get())));
  166.             } else {
  167.                 fut.value = new Some(Try.doWork(() => {
  168.                     throw from.value.get().failed().get();
  169.                 }));
  170.             }
  171.  
  172.             fut.flatRun();
  173.         };
  174.         return fut;
  175.     }
  176.  
  177.     onFailed<S>(f: (T) => S): Future<S> {
  178.         let from = this;
  179.         let fut = new Future<S>(() => {
  180.             return f(from.value.get());
  181.         }, this.executor);
  182.         fut.parent = this;
  183.         this.next = () => {
  184.             if (from.value.get().isFailure()) {
  185.                 fut.value = new Some(Try.doWork(() => {
  186.                     f(from.value.get().failed().get());
  187.                     throw from.value.get().failed().get();
  188.                 }));
  189.             } else {
  190.                 fut.value = from.value as Option<Try<any>> as Option<Try<S>>;
  191.                 /*fut.value = new Some(Try.doWork(() => {
  192.                     //fut.value = new Some(from.value.get().get());
  193.                     //throw from.value.get().get();
  194.                 }))*/
  195.             }
  196.  
  197.             fut.flatRun();
  198.         };
  199.         return fut;
  200.     }
  201.  
  202.  
  203.     //------------------------------- INTERNAL API ------------------------------------
  204.  
  205.     /** Execute future on the execution context */
  206.     private flatRun() {
  207.         if (this.value.isEmpty()) {
  208.             this.executor.registerForExecution(() => {
  209.                 if (this.f != null) {
  210.                     this.value = new Some(Try.doWork(() => this.f()));
  211.                 }
  212.  
  213.                 if (this.next != null) {
  214.                     this.next();
  215.                 }
  216.             });
  217.         } else {
  218.             if (this.next != null) {
  219.                 this.next();
  220.             }
  221.         }
  222.     }
  223.  
  224.     /** Go through the futures chain to the root future and start it execution */
  225.     private execRoot() {
  226.         if (this.parent == null) {
  227.             this.flatRun();
  228.         } else {
  229.             this.parent.execRoot();
  230.         }
  231.     }
  232.  
  233.     /** Used if future is promise Go through the futures chain to the root future and start it execution
  234.      *  with presented value */
  235.     private execRootPromise(value: Try<T>) {
  236.         if (this.parent == null) {
  237.             this.value = new Some(value);
  238.             this.flatRun();
  239.         } else {
  240.             this.parent.execRootPromise(value);
  241.         }
  242.     }
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement