Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

You had just realized factory of deffered and named in Promise... #164

Open
6562680 opened this issue Nov 26, 2023 · 0 comments
Open

You had just realized factory of deffered and named in Promise... #164

6562680 opened this issue Nov 26, 2023 · 0 comments

Comments

@6562680
Copy link

6562680 commented Nov 26, 2023

Look the promise power in JS:

  <script>
    (function () {
      function map1(data)
      {
        throw [ new Error('map1.error'), data ];
        return data + 1;
      }
      function map2(data)
      {
        // throw [ new Error('map2.error'), data ];
        return data + 1;
      }
      function map3(data)
      {
        throw [ new Error('map3.error'), data ];
        return data + 1;
      }

      const pf = (() => new Promise((ok) => {
        throw [ new Error('p.error'), 1 ];
        ok(1);
      }));

      pf()
        .catch(([ e, data ]) => {
          console.error(e);
          return data;
        })
        .then(map1)
        .catch(([ e, data ]) => {
          console.error(e);
          return data;
        })
        .then(map2)
        .catch(([ e, data ]) => {
          console.error(e);
          return data;
        })
        .then(map3)
        .catch(([ e, data ]) => {
          console.error(e);
          return data;
        })
        .then(console.info)
        .catch(([ e, data ]) => {
          console.error(e);
          return data;
        });
    })();
  </script>

Look the code in PHP:

<?php
use GuzzleHttp\Promise\Promise;

require_once __DIR__ . '/vendor/autoload.php';

class MyException extends \RuntimeException
{
  protected $data;

  public function __construct(
      array $messageData,
      $code = 0,
      Throwable $previous = null
  )
  {
      [ $message, $data ] = $messageData;

      $this->data = $data;

      parent::__construct($message, $code, $previous);
  }

  public function getData()
  {
      return $this->data;
  }
}


function map1($data)
{
  throw new MyException([ 'map1.error', $data ]);

  return $data + 1;
}

function map2($data)
{
  throw new MyException([ 'map2.error', $data ]);

  return $data + 1;
}

function map3($data)
{
  throw new MyException([ 'map3.error', $data ]);

  return $data + 1;
}

function onError(\Throwable $e)
{
  $data = null;
  if ($e instanceof MyException) {
      $data = $e->getData();
  }

  var_dump($e);

  return $data;
}


$pf = function () : Promise {
  return $promise = new Promise(function () use (&$promise) {
      throw new MyException([ 'p.error', 1 ]);

      $promise->resolve(1);
  });
};

$promise = $pf();
$promise
  ->then('map1', 'onError')
  ->then('map2', 'onError')
  ->then('map3', 'onError')
;
$promise->wait(); // throws an exception... breaks your pipeline at all

// requires to try/catch block everywhere in the code and makes your library like "async" call support (that could be made with \Generator that is bundled)
// so you created Factory for Deferreds with uncomfortable async support because the php is a heck for now...

Reasons:

  1. Promise runs immediately and takes as argument $fnOk and $fnFail, so if you want to call it later - you wrap "new Promise" to function, that gives you the Task (delayed call)
  2. Promise has the CHAINED call ->catch(), allows you to handle error, and then CONTINUE chain or if you define catch block near original call you could define retry step right there
  3. Javascript allows you to throw array instead of wrap exception in exception, so this FEATURE you have to realize manually to simplify code-(reading|writing), you need to create your own SUGAR, because PHP-devs is trapped to community voting idea (that day-to-day signalled about php is died forever)
  4. Yes, Javascript has a problem that initially promise CANNOT be resolved outside init function, so it requires to create Deferred as a Promise decorator. Guess you need to realize both of them, cus of Deferreds is needed to connect two modules via Event, instead Promise - gives you chained (and possible async) calling of your pipeline.
  5. Main idea of whole code in the world "do not change library code but allow me to customise behavior of it and save my written code almost untouched." It usually could be solved in OOP paradigm with decorating classes methods etc, but mass problem of OOP is a VERY SMALL METHODS that is VERY MANY COUNT of. Fast refactoring requires change few lines of existing code, but OOP forces to rewrite all. Thats why the Pipeline idea (that is used in raw electricity btw) is a required stuff, if you write your controllers in pipeline paradigm you dont change even count of spaces, dont add any curly braces or something, you add catch block for problem place and you're done.

So your library is a Deferred factory without exception catching and without known sugar for js devs.

And can be simplified with:

function controller()
{
  $readln = false;
  foreach ($gen = chainedAction($readln) as $event => $eventData) {
    $readln = false;
    if ($event === 'state1') {
      (function ($eventData) { /* ...do some side effect (event-handler) */ })($eventData); 

    } elseif ($event === 'state2') {
      $readln = true;
      $gen->send($eventData + 2); // ...prepare data to return it back (pipeline/command-handler)
    }
  }
}

function chainedAction(bool &$readln) : iterable
{
  $data = 0;

  yield 'state1' => $data;
  if ($readln) $data = yield;

  $data++;

  yield 'state2' => $data;
  if ($readln) $data = yield;

  $data++;

  yield 'state3' => $data;
  if ($readln) $data = yield;
}

So common way of refactoring in Javascript is a like this (pseudo-code):

use Library; // guess library hadn't written in Promise paradigm at all, only sync...

function controller()
{
  $result = Library::call(...someArgs); // devs spotted unexpected error something here
  anotherAction($result);
}

async function newController()
{
  $result = await Promise.resolve()
    .catch('functionThatCatchAndChangesResultToKnownDefault')
    .then('anotherAction');

  return result;
}

async function newControllerInPhp()
{
  try {
    $result = Library::call(...someArgs); // devs spotted unexpected error something here
  } catch (\Throwable $e) {
    // logger
    // sentry
    // ...tonns of methods that you forget guaranteed
    // ...and the problem is in that, so you ALWAYS needed to write try/catch block making your code like scratch with this hell
    $result = $resultDefault;
  }

  anotherAction($result);

  return result;
}

function libraryCall(...args)
{
  return new Promise((ok) => ok(Library::call(...args));
}

Lets talk?
t.me/gzhegow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant