Weave Code
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 lightweight, dependency-free library.

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

    use PhpStandardLibrary\Promise\Promise;
    
    $promise = new Promise(function ($resolve, $reject) {
        // Simulate async operation (e.g., API call, DB query)
        if ($someCondition) {
            $resolve("Success!");
        } else {
            $reject(new \Exception("Failed!"));
        }
    });
    
    // Attach callbacks
    $promise->then(function ($result) {
        echo "Resolved: " . $result;
    })->catch(function (\Throwable $e) {
        echo "Rejected: " . $e->getMessage();
    });
    
  3. First Use Case: Wrap a Laravel queue job or HTTP request to chain async operations:

    use Illuminate\Support\Facades\Http;
    use PhpStandardLibrary\Promise\Promise;
    
    $promise = new Promise(function ($resolve) {
        $response = Http::get('https://api.example.com/data');
        $resolve($response->json());
    });
    
    $promise->then(function ($data) {
        // Process data synchronously
        return User::createFromApiData($data);
    })->then(function ($user) {
        echo "User created: " . $user->name;
    });
    
  4. Where to Look First:

    • Documentation: PHP Standard Library Docs (focus on the Promise section).
    • Source Code: Promise.php for implementation details.
    • Examples: Check the tests/ directory in the repo for usage patterns.

Implementation Patterns

Core Workflows

1. Chaining Async Operations

Use .then() to chain dependent async tasks (e.g., API calls, DB operations):

$promise = new Promise(function ($resolve) {
    $resolve(fetchUserData());
})->then(function ($user) {
    return fetchUserOrders($user->id); // Returns a new Promise
})->then(function ($orders) {
    return processOrders($orders);
})->catch(function (\Throwable $e) {
    Log::error("Async chain failed: " . $e->getMessage());
});

2. Parallel Execution with Promise::all()

Run multiple async operations in parallel and wait for all to complete:

use PhpStandardLibrary\Promise\Promise;

$promise1 = new Promise(function ($resolve) {
    $resolve(fetchData('users'));
});

$promise2 = new Promise(function ($resolve) {
    $resolve(fetchData('orders'));
});

Promise::all([$promise1, $promise2])->then(function ($results) {
    $users = $results[0];
    $orders = $results[1];
    // Combine results
});

3. Race Conditions with Promise::race()

Resolve as soon as one of the promises settles (useful for timeouts):

$promise1 = new Promise(function ($resolve) {
    sleep(2);
    $resolve("Slow result");
});

$promise2 = new Promise(function ($resolve) {
    $resolve("Fast result");
});

Promise::race([$promise1, $promise2])->then(function ($result) {
    echo "First to resolve: " . $result; // "Fast result"
});

4. Wrapping Laravel Components

  • Queue Jobs:
    $jobPromise = new Promise(function ($resolve) {
        $job = new ProcessOrdersJob($orderId);
        dispatch($job)->onQueue('promises');
        $resolve($job); // Resolve when job completes (requires event/listener)
    });
    
  • HTTP Clients:
    $httpPromise = new Promise(function ($resolve) use ($client) {
        $response = $client->get('/api/data');
        $resolve($response->json());
    });
    

5. Error Handling

  • Global Unhandled Rejections:
    Promise::setUnhandledRejectionHandler(function (\Throwable $e) {
        Log::critical("Unhandled Promise rejection: " . $e->getMessage());
        // Optionally notify monitoring tools (e.g., Sentry)
    });
    
  • Retry Logic:
    function retryPromise($promise, $maxRetries = 3) {
        return $promise->catch(function (\Throwable $e) use ($promise, $maxRetries) {
            if ($maxRetries <= 0) throw $e;
            return retryPromise($promise, $maxRetries - 1);
        });
    }
    

Integration Tips

Laravel-Specific Patterns

  1. Service Providers: Bind the Promise class to the container for easy access:

    // app/Providers/AppServiceProvider.php
    public function register() {
        $this->app->singleton('promise', function () {
            return new \PhpStandardLibrary\Promise\Promise();
        });
    }
    

    Use via app('promise') or create a facade.

  2. Macros for Laravel: Extend Laravel’s Bus or Queue to return Promises:

    // app/Helpers/PromiseHelper.php
    if (!function_exists('promiseDispatch')) {
        function promiseDispatch($job, $queue = null) {
            return new \PhpStandardLibrary\Promise\Promise(function ($resolve) use ($job, $queue) {
                dispatch($job)->onQueue($queue)->afterResolved(function () use ($resolve) {
                    $resolve(true);
                });
            });
        }
    }
    
  3. Testing Promises: Use Mockery to stub Promise resolutions:

    $mockPromise = Mockery::mock(\PhpStandardLibrary\Promise\Promise::class);
    $mockPromise->shouldReceive('then')->once()->withAnyArgs();
    $mockPromise->shouldReceive('catch')->never();
    
  4. Async Event Listeners: Convert sync event listeners to async with Promises:

    Event::listen(OrderPlaced::class, function () {
        $promise = new Promise(function ($resolve) {
            $resolve(notifyCustomer());
        });
        return $promise; // Return Promise for chaining
    });
    

Performance Considerations

  • Avoid Blocking: Never call .then() synchronously in a loop (e.g., Promise::all(array_map(...)) can block).
  • Batch Promises: For high-throughput systems, batch Promise::all() calls to avoid memory spikes.
  • Lazy Resolution: Defer Promise resolution until absolutely necessary (e.g., resolve only when data is needed).

Gotchas and Tips

Pitfalls

  1. Callback Hell Revisited:

    • Issue: Deeply nested .then() chains can still resemble callback hell.
    • Fix: Use combinators like Promise::all() or flatten chains with Promise::then() returning Promises.
  2. Unresolved Promises:

    • Issue: Forgotten Promises (e.g., returned but never resolved) can cause memory leaks.
    • Fix: Always attach a .finally() or use a TTL (e.g., finally(fn() => $promise->cancel())).
  3. Error Propagation:

    • Issue: Errors in .then() callbacks may not bubble up correctly if not wrapped in try/catch.
    • Fix: Use Promise::catch() after every .then() or wrap callbacks in try/catch.
  4. PHP’s Async Limitations:

    • Issue: Promises alone don’t run async—they defer execution to callbacks. Without an event loop (e.g., ReactPHP), Promises won’t parallelize work.
    • Fix: Use Laravel Queues or external event loops for true concurrency.
  5. Global State:

    • Issue: Shared resolvers/rejectors can cause race conditions.
    • Fix: Encapsulate Promise logic in classes or closures.
  6. Testing Complexity:

    • Issue: Mocking Promises requires stubbing both .then() and .catch() paths.
    • Fix: Use Mockery or create a PromiseTestCase helper:
      $promise = new Promise(function ($resolve) { $resolve("test"); });
      $promise->then($this->expectsOnce()->with("test"));
      

Debugging Tips

  1. Log Promise States:

    $promise->then(function ($result) {
        Log::debug("Promise resolved", ['result' => $result]);
    })->catch(function (\Throwable $e) {
        Log::error("Promise rejected", ['error' => $e->getMessage()]);
    });
    
  2. Xdebug for Async:

    • Use Xdebug with async stack traces to inspect Promise chains.
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope