You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用wire:poll展示循环处理任务进度:实时更新失效问题咨询

问题

开发批量任务处理应用时,希望通过wire:poll实时展示处理进度,但点击提交后$number始终显示0,直到循环结束直接跳转为10,wire:poll无法捕获$numberProcessed的实时更新。

复现代码

Livewire组件(ProcessItems.php)

<?php
namespace App\Livewire;
use Livewire\Component;

class ProcessItems extends Component
{
    public $numberProcessed = 0;

    public function process()
    {
        for($i = 0; $i < 10; $i++) {
            sleep(1);
            $this->numberProcessed++;
        }
    }

    public function render()
    {
        return view('livewire.process-items', [
            'number' => $this->numberProcessed,
        ]);
    }
}

Blade视图(process-items.blade.php)

<div>
    <form wire:submit="process()">
        <div class="pt-4">
            <x-primary-button class="ml-0">
                {{ __('Submit') }}
            </x-primary-button>
        </div>
    </form>
    <div wire:poll>
        Items processed: {{ $number }}
    </div>
</div>

原因及解决方案

核心原因

Livewire的同步请求是阻塞式的:触发process方法后,服务器会完整执行整个循环才返回响应,期间组件状态更新不会实时推送给前端。wire:poll的轮询请求会被当前请求阻塞,直到循环结束后一次性更新数值。

解决方法

方法1:浏览器事件实时推送

在循环中通过dispatchBrowserEvent向前端发送进度,前端直接修改DOM,无需依赖wire:poll:

修改Livewire组件:

public function process()
{
    for($i = 0; $i < 10; $i++) {
        sleep(1);
        $this->numberProcessed++;
        // 发送进度更新事件
        $this->dispatchBrowserEvent('update-progress', [
            'count' => $this->numberProcessed
        ]);
    }
}

修改Blade视图:

<div>
    <form wire:submit="process()">
        <div class="pt-4">
            <x-primary-button class="ml-0">
                {{ __('Submit') }}
            </x-primary-button>
        </div>
    </form>
    <div id="progress">
        Items processed: {{ $number }}
    </div>

    <script>
        document.addEventListener('livewire:initialized', () => {
            Livewire.on('update-progress', (data) => {
                document.getElementById('progress').textContent = `Items processed: ${data.count}`;
            });
        });
    </script>
</div>

方法2:队列任务+wire:poll轮询

把批量处理逻辑放到Laravel队列,组件通过wire:poll定期读取缓存中的进度:

  1. 创建队列任务类(ProcessBatchItems.php):
<?php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessBatchItems implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle()
    {
        for($i = 0; $i < 10; $i++) {
            sleep(1);
            // 将进度存入缓存
            cache()->put('batch_progress', $i+1, now()->addMinutes(5));
        }
        // 任务完成后清理缓存
        cache()->forget('batch_progress');
    }
}
  1. 修改Livewire组件:
public $numberProcessed = 0;

public function process()
{
    // 初始化进度为0
    cache()->put('batch_progress', 0, now()->addMinutes(5));
    // 分发队列任务
    dispatch(new \App\Jobs\ProcessBatchItems());
}

public function render()
{
    // 从缓存读取最新进度
    $this->numberProcessed = cache()->get('batch_progress', 0);
    return view('livewire.process-items', [
        'number' => $this->numberProcessed,
    ]);
}

视图保留原wire:poll即可,每次轮询会自动拉取最新进度。

方法3:Livewire 3后台任务(推荐)

如果使用Livewire 3,可利用内置后台任务功能,无需额外队列配置:

修改Livewire组件:

use Livewire\Attributes\Background;
use Livewire\Attributes\On;

public $numberProcessed = 0;

#[Background]
public function process()
{
    for($i = 0; $i < 10; $i++) {
        sleep(1);
        $this->numberProcessed++;
        // 推送更新事件触发组件刷新
        $this->dispatch('progress-updated');
    }
}

#[On('progress-updated')]
public function refreshProgress()
{
    // 触发组件重新渲染
    $this->render();
}

视图保留wire:poll或依赖事件触发更新均可,后台任务执行时会实时推送状态。


内容的提问来源于stack exchange,提问作者Martin J. Osborne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:40:10