Skip to content

Производительность: extend_cart_data() кладёт весь список ПВЗ в каждый ответ Store API /cart (блочный чекаут) #148

Description

@dzvtr

Проблема

На блочном чекауте (WooCommerce Checkout block / Store API) метод CheckoutMapBlock::extend_cart_data() (src/Blocks/CheckoutMapBlock.php) регистрируется через woocommerce_store_api_register_endpoint_data() на схему корзины (CartSchema) и возвращает поле points = весь JSON-список ПВЗ выбранного города ($api->officeListRaw($city)).

Это поле попадает в каждый ответ GET /wp-json/wc/store/v1/cart. Блочный чекаут перезапрашивает /cart многократно (при загрузке страницы и при любом update — десятки запросов за сессию оформления), поэтому один и тот же большой payload со списком ПВЗ передаётся по сети снова и снова.

Замеры

После ввода города ответ /cart раздувается с ~13 КБ до ~1 МБ (для крупного города — весь список пунктов выдачи; у нас фиксировали ~1.14 МБ). На пустой корзине / без города — норма (points: "[]").

Влияние

  • заметное замедление и подтормаживание страницы оформления, особенно на мобильных и медленных соединениях;
  • многократный лишний трафик (одни и те же ~1 МБ в каждом опросе /cart);
  • если officeListRaw() не кэшируется — ещё и повторные обращения к api.cdek.ru на каждый запрос.

Вероятно, это же является корнем #131 (много запросов / долгая загрузка), но там симптом описан на странице каталога — здесь конкретно про размер payload Store API /cart на чекауте.

Код (5.0.0)

public static function extend_cart_data(): array
{
    $cityInput     = CheckoutHelper::getCurrentValue('city');
    $postcodeInput = CheckoutHelper::getCurrentValue('postcode');

    if (empty($cityInput)) {
        return ['points' => '[]'];
    }

    $api = new CdekApi;
    try {
        $city   = $api->cityCodeGet($cityInput, $postcodeInput);
        $points = $city !== null ? $api->officeListRaw($city) : '[]';
    } catch (ExceptionContract $e) {
        $city   = null;
        $points = '[]';
    }

    return [
        'inputs' => ['city' => $cityInput, 'postcode' => $postcodeInput],
        'city'   => $city,
        'points' => $points, // весь список ПВЗ города — в каждом ответе /cart
    ];
}

Окружение

  • CDEKDelivery 5.0.0
  • WooCommerce 10.9.1, WordPress 7.0, PHP 8.3.31
  • Чекаут — блочный (Store API /wp-json/wc/store/v1/cart)

Как воспроизвести

  1. Блочный чекаут, товар в корзине.
  2. Ввести город доставки.
  3. В DevTools → Network посмотреть ответы GET /wp-json/wc/store/v1/cart: в extensions.official_cdek.points — весь список ПВЗ (~1 МБ), и он повторяется в каждом из множества запросов /cart.

Ожидаемое поведение / предложение по исправлению

Не вкладывать полный список ПВЗ в расширение CartSchema, отдаваемое на каждый /cart. Варианты:

  1. вынести список ПВЗ в отдельный on-demand REST-эндпоинт, который фронтенд запрашивает один раз при открытии карты выбора пункта выдачи;
  2. либо отдавать points только при фактической смене города, а не в каждом ответе;
  3. как минимум — серверное кэширование списка ПВЗ и/или отдача компактного набора полей.

Готовы предоставить HAR и тайминги при необходимости. Спасибо!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions