Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Promise Laravel Package

php-standard-library/promise

Lightweight Promise implementation for PHP with a simple, standards-inspired API. Create, resolve, reject, and chain async-style operations, handle errors, and compose results with familiar then/catch patterns—ideal for libraries that need non-blocking workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require php-standard-library/promise
    

    No additional configuration is required—it’s a dependency-free, standalone library.

  2. Basic Usage: Start with a simple deferred computation:

    use PhpStandardLibrary\Promise\Promise;
    
    // Create a new promise
    $promise = new Promise(function ($resolve, $reject) {
        // Simulate async work (e.g., API call, DB query)
        if (rand(0, 1)) {
            $resolve("Success!");
        } else {
            $reject(new \RuntimeException("Failed!"));
        }
    });
    
    // Attach callbacks
    $promise->then(
        function ($value) {
            echo "Resolved: " . $value;
        },
        function (\Throwable $error) {
            echo "Rejected: " . $error->getMessage();
        }
    );
    
  3. First Use Case: Wrap a Laravel queue job or external API call to chain async operations:

    use PhpStandardLibrary\Promise\Promise;
    use Illuminate\Support\Facades\Http;
    
    $apiPromise = new Promise(function ($resolve, $reject) {
        $response = Http::get('https://api.example.com/data');
        if ($response->successful()) {
            $resolve($response->json());
        } else {
            $reject(new \Exception("API request failed"));
        }
    });
    
    $apiPromise->then(
        function ($data) {
            // Process data or dispatch a follow-up job
            dispatch(new ProcessDataJob($data));
        }
    );
    
  4. Key Entry Points:

    • Promise::all(): Wait for multiple promises to resolve.
    • Promise::race(): Resolve/reject as soon as one promise settles.
    • Promise::reject()/Promise::resolve(): Create settled promises directly.

Implementation Patterns

Core Workflows

1. Sequential Async Chaining

Replace nested callbacks with .then() chains:

$promise1 = new Promise(...);
$promise2 = new Promise(...);

$promise1->then(
    function ($result) {
        return new Promise(function ($resolve) use ($result) {
            // Async step 2
            $resolve($result . "_processed");
        });
    }
)->then(function ($finalResult) {
    // Final step
});

2. Parallel Execution with Promise::all()

Run multiple async operations concurrently:

$promise1 = fetchUserData();
$promise2 = fetchOrderData();
$promise3 = fetchPaymentData();

Promise::all([$promise1, $promise2, $promise3])->then(function ($results) {
    // $results = [userData, orderData, paymentData]
});

3. Error Handling Strategies

  • Global Handler: Attach to all promises:
    Promise::setUnhandledRejectionHandler(function (\Throwable $error) {
        \Log::error("Unhandled rejection: " . $error->getMessage());
    });
    
  • Per-Promise: Use .catch() or the second argument in .then():
    $promise->then(
        function ($value) {},
        function (\Throwable $error) {
            \Log::error($error);
        }
    );
    

4. Laravel Integration

  • Queue Jobs:
    $jobPromise = new Promise(function ($resolve) {
        dispatch(new LongRunningJob())->onQueue('promises');
        $resolve("Job dispatched");
    });
    
  • HTTP Clients:
    $responsePromise = new Promise(function ($resolve, $reject) {
        $response = Http::get('...');
        $resolve($response->json());
    });
    

5. Combinators

  • Race: First to settle wins:
    Promise::race([$promise1, $promise2])->then(...);
    
  • Any: Resolve if any promise resolves (rejects if all reject):
    Promise::any([$promise1, $promise2])->then(...);
    

Laravel-Specific Patterns

Promise-Aware Facades

Extend Laravel’s Bus or Queue to return promises:

// app/Providers/AppServiceProvider.php
use PhpStandardLibrary\Promise\Promise;
use Illuminate\Support\Facades\Bus;

Bus::macro('promise', function ($command) {
    return new Promise(function ($resolve, $reject) {
        try {
            $response = Bus::dispatch($command);
            $resolve($response);
        } catch (\Throwable $e) {
            $reject($e);
        }
    });
});

Usage:

Bus::promise(new ProcessOrder())->then(...);

Custom Promise Helpers

Create domain-specific combinators:

// app/Support/PromiseHelpers.php
use PhpStandardLibrary\Promise\Promise;

class PromiseHelpers {
    public static function allSettled(array $promises) {
        return Promise::all(array_map(function ($promise) {
            return $promise->then(
                fn($value) => ['status' => 'fulfilled', 'value' => $value],
                fn(\Throwable $error) => ['status' => 'rejected', 'reason' => $error]
            );
        }, $promises));
    }
}

Testing Promises

Use Mockery to stub promises in tests:

$mockPromise = Mockery::mock(Promise::class);
$mockPromise->shouldReceive('then')
    ->once()
    ->withAnyArgs()
    ->andReturnSelf();
$mockPromise->shouldReceive('resolve')->once()->with('test');

// In test
$promise = new Promise(...);
$promise->then(function ($value) {
    $this->assertEquals('test', $value);
});

Gotchas and Tips

Pitfalls

  1. Unresolved Promises Leak Memory

    • Issue: Promises that are never resolved/rejected can cause memory leaks.
    • Fix: Always attach a .finally() or use a timeout:
      $promise->finally(function () {
          // Cleanup (e.g., close DB connections)
      });
      
    • Laravel Tip: Combine with Laravel’s withTimeout() for queue jobs.
  2. Callback Hell in Disguise

    • Issue: Deeply nested .then() chains defeat the purpose of Promises.
    • Fix: Flatten chains using Promise::all() or extract logic into helper functions.
  3. Global State in Promises

    • Issue: Shared resolvers/rejectors can cause race conditions.
    • Fix: Avoid global variables; pass dependencies explicitly.
  4. Error Handling Gaps

    • Issue: Unhandled rejections may crash Laravel’s request lifecycle.
    • Fix: Use setUnhandledRejectionHandler and log errors to Sentry/Telescope:
      Promise::setUnhandledRejectionHandler(function (\Throwable $error) {
          \Sentry\captureException($error);
      });
      
  5. Blocking the Event Loop (Indirectly)

    • Issue: Long-running Promise callbacks can block Laravel’s synchronous flow.
    • Fix: Offload heavy work to queues or use defer():
      $promise->then(function () {
          \Illuminate\Support\Facades\Bus::defer(fn() => $heavyTask());
      });
      

Debugging Tips

  1. Log Promise States Extend the Promise class to log resolutions/rejections:

    class DebugPromise extends Promise {
        public function __construct(callable $executor) {
            parent::__construct(function ($resolve, $reject) use ($executor) {
                \Log::debug("Promise created");
                $executor(function ($value) use ($resolve) {
                    \Log::debug("Promise resolved: " . json_encode($value));
                    $resolve($value);
                }, function (\Throwable $error) use ($reject) {
                    \Log::error("Promise rejected: " . $error->getMessage());
                    $reject($error);
                });
            });
        }
    }
    
  2. Use Telescope for Monitoring Create a custom Telescope channel to track Promise activity:

    // app/Providers/TelescopeServiceProvider.php
    use Illuminate\Support\Facades\Telescope;
    
    Telescope::macro('promise', function ($promise) {
        $promise->then(
            fn($value) => Telescope::log('Promise resolved', ['value' => $value]),
            fn(\Throwable $error) => Telescope::log('Promise rejected', ['error' => $error->getMessage()])
        );
    });
    
  3. Xdebug Async Support For local debugging, use Xdebug’s async stack traces:

    xdebug.mode=debug
    xdebug
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style