Example #1
0
 /**
  * Emits a value from the observable. The returned promise is resolved with the emitted value once all subscribers
  * have been invoked.
  *
  * @param mixed $value
  *
  * @return \Interop\Async\Promise
  *
  * @throws \Error If the observable has resolved.
  */
 private function emit($value) : Promise
 {
     if ($this->resolved) {
         throw new \Error("The observable has been resolved; cannot emit more values");
     }
     if ($value instanceof Promise) {
         $deferred = new Deferred();
         $value->when(function ($e, $v) use($deferred) {
             if ($this->resolved) {
                 $deferred->fail(new \Error("The observable was resolved before the promise result could be emitted"));
                 return;
             }
             if ($e) {
                 $this->fail($e);
                 $deferred->fail($e);
                 return;
             }
             $deferred->resolve($this->emit($v));
         });
         return $deferred->promise();
     }
     $promises = [];
     foreach ($this->subscribers as $onNext) {
         try {
             $result = $onNext($value);
             if ($result instanceof Promise) {
                 $promises[] = $result;
             }
         } catch (\Throwable $e) {
             Loop::defer(static function () use($e) {
                 throw $e;
             });
         }
     }
     if (!$promises) {
         return new Success($value);
     }
     $deferred = new Deferred();
     $count = \count($promises);
     $f = static function ($e) use($deferred, $value, &$count) {
         if ($e) {
             Loop::defer(static function () use($e) {
                 throw $e;
             });
         }
         if (!--$count) {
             $deferred->resolve($value);
         }
     };
     foreach ($promises as $promise) {
         $promise->when($f);
     }
     return $deferred->promise();
 }
Example #2
0
/**
 * Create an artificial timeout for any Promise instance
 *
 * If the timeout expires prior to promise resolution the returned
 * promise is failed.
 *
 * @param \Amp\Promise $promise The promise to which the timeout applies
 * @param int $msTimeout The timeout in milliseconds
 * @return \Amp\Promise
 */
function timeout(Promise $promise, $msTimeout)
{
    $resolved = false;
    $promisor = new Deferred();
    $watcherId = once(function () use($promisor, &$resolved) {
        $resolved = true;
        $promisor->fail(new TimeoutException("Promise resolution timed out"));
    }, $msTimeout);
    $promise->when(function ($error = null, $result = null) use($promisor, $watcherId, &$resolved) {
        if ($resolved) {
            return;
        }
        $resolved = true;
        cancel($watcherId);
        if ($error) {
            $promisor->fail($error);
        } else {
            $promisor->succeed($result);
        }
    });
    return $promisor->promise();
}
Example #3
0
/**
 * Returns a promise that succeeds or fails when the first promise succeeds or fails.
 *
 * @param Promise[] $promises
 *
 * @return \Interop\Async\Promise
 *
 * @throws \Error If the array is empty or a non-Promise is in the array.
 */
function choose(array $promises) : Promise
{
    if (empty($promises)) {
        throw new \Error("No promises provided");
    }
    $deferred = new Deferred();
    $resolved = false;
    foreach ($promises as $promise) {
        if (!$promise instanceof Promise) {
            throw new \Error("Non-promise provided");
        }
        $promise->when(function ($exception, $value) use(&$resolved, $deferred) {
            if ($resolved) {
                return;
            }
            $resolved = true;
            if ($exception) {
                $deferred->fail($exception);
                return;
            }
            $deferred->resolve($value);
        });
    }
    return $deferred->promise();
}