GSP
Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Support
Contact Us
Online Help
Handbooks
Domain Status
Man Pages

FAQ
Virtual Servers
Pricing
Billing
Technical

Network
Facilities
Connectivity
Topology Map

Miscellaneous
Server Agreement
Year 2038
Credits
 

USA Flag

 

 

Man Pages
Promises::Cookbook::TIMTOWTDI(3) User Contributed Perl Documentation Promises::Cookbook::TIMTOWTDI(3)

Promises::Cookbook::TIMTOWTDI - Counter examples to Promises

version 0.94

So, like I said before, Promises are a means by which you can more effectively manage your async operations and avoid callback spaghetti. But of course this is Perl and therefore there is always another way to do it. In this section I am going to show a few examples of other ways you could accomplish the same thing.

Please note that I am specifically illustrating ways to do this which I feel are inferior or less elegant then Promises. This is not meant to be a slight on the API of other modules at all, I am simply using these modules to try and illustrate other (perhaps more familiar) idioms in hopes that it will help people understand Promises.

I am sure there are other ways to do some of these things and do them more effectively, and I am fully willing to admit my ignorance here. I welcome any patches which might illustrate said ignorance, as I do not claim at all to be an expert in async programming.

So, enough caveating, please consider this (more traditional) version of our the Promises SYNOPSIS example using AnyEvent::HTTP.

  my $cv = AnyEvent->condvar;

  http_get('http://rest.api.example.com/-/product/12345', sub {
      my ($product) = @_;
      http_get('http://rest.api.example.com/-/product/suggestions?for_sku=12345', sub {
          my ($suggestions) = @_;
          http_get('http://rest.api.example.com/-/product/reviews?for_sku=12345', sub {
              my ($reviews) = @_;
              $cv->send({
                  product     => $product,
                  suggestions => $suggestions,
                  reviews     => $reviews,
              })
          }),
      });
  });

  my $all_product_info = $cv->recv;

Not only do we have deeply nested callbacks, but we have an enforced order of operations. If you wanted to try and avoid that order of operations, you might end up writing something like this:

   my $product_cv    = AnyEvent->condvar;
   my $suggestion_cv = AnyEvent->condvar;
   my $review_cv     = AnyEvent->condvar;

   http_get('http://rest.api.example.com/-/product/12345', sub {
       my ($product) = @_;
       $product_cv->send( $product );
   });

   http_get('http://rest.api.example.com/-/product/suggestions?for_sku=12345', sub {
       my ($suggestions) = @_;
       $suggestion_cv->send( $suggestions );
   });

   http_get('http://rest.api.example.com/-/product/reviews?for_sku=12345', sub {
       my ($reviews) = @_;
       $reviews_cv->send( $reviews )
   }),

   my $all_product_info = {
       product     => $product_cv->recv,
       suggestions => $suggestions_cv->recv,
       reviews     => $reviews_cv->recv
   };

But actually, this doesn't work either, while we do gain something by allowing the "http_get" calls to be run in whatever order works best, we still end up still enforcing some order in the way we call "recv" on our three "condvars" (Oh yeah, and we had to create and manage three "condvars" as well).

The following example was submitted to me by James Wright (via RT #83992) as an alternate approach which is non-nested, uses only one condvar, and has no fixed-order.

  my $cv = AnyEvent->condvar;
  my ( $product, $suggestions, $reviews ) = ( [], [], [] );

  $cv->begin;
  http_get('http://rest.api.example.com/-/product/12345', sub {
      ($product) = @_;
      $cv->end;
  });

  $cv->begin;
  http_get('http://rest.api.example.com/-/product/suggestions?for_sku=12345', sub {
      ($suggestions) = @_;
      $cv->end;
  });

  $cv->begin;
  http_get('http://rest.api.example.com/-/product/reviews?for_sku=12345', sub {
      ($reviews) = @_;
      $cv->end;
  });

  $cv->cb(sub {
      $cv->send({
          product     => $product,
          suggestions => $suggestions,
          reviews     => $reviews,
      });
  });

  my $all_product_info = $cv->recv;

The only real issue I have with this approach is the semi-global variable usage ($product, $suggestions and $reviews), but otherwise it works fine.

NOTE: Again, if can think of a better way to do this that I missed, please let me know.

... TODO

Stevan Little <stevan.little@iinteractive.com>

This software is copyright (c) 2014 by Infinity Interactive, Inc..

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

2014-12-28 perl v5.32.1

Search for    or go to Top of page |  Section 3 |  Main Index

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.