Skip to content

Commit

Permalink
Add performance measurement to Cart AJAX
Browse files Browse the repository at this point in the history
  • Loading branch information
haeky committed Feb 7, 2025
1 parent bbfd08b commit 5be4190
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 52 deletions.
108 changes: 58 additions & 50 deletions assets/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class CartRemoveButton extends HTMLElement {
this.addEventListener('click', (event) => {
event.preventDefault();
const cartItems = this.closest('cart-items') || this.closest('cart-drawer-items');
cartItems.updateQuantity(this.dataset.index, 0);
cartItems.updateQuantity(this.dataset.index, 0, event);
});
}
}
Expand Down Expand Up @@ -76,6 +76,7 @@ class CartItems extends HTMLElement {
this.updateQuantity(
index,
inputValue,
event,
document.activeElement.getAttribute('name'),
event.target.dataset.quantityVariantId
);
Expand Down Expand Up @@ -143,7 +144,7 @@ class CartItems extends HTMLElement {
];
}

updateQuantity(line, quantity, name, variantId) {
updateQuantity(line, quantity, event, name, variantId) {
this.enableLoading(line);

const body = JSON.stringify({
Expand All @@ -152,60 +153,66 @@ class CartItems extends HTMLElement {
sections: this.getSectionsToRender().map((section) => section.section),
sections_url: window.location.pathname,
});
const eventTarget = event.currentTarget instanceof CartRemoveButton ? 'clear' : 'change';

fetch(`${routes.cart_change_url}`, { ...fetchConfig(), ...{ body } })
.then((response) => {
return response.text();
})
.then((state) => {
const parsedState = JSON.parse(state);
const quantityElement =
document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`);
const items = document.querySelectorAll('.cart-item');

if (parsedState.errors) {
quantityElement.value = quantityElement.getAttribute('value');
this.updateLiveRegions(line, parsedState.errors);
return;
}

this.classList.toggle('is-empty', parsedState.item_count === 0);
const cartDrawerWrapper = document.querySelector('cart-drawer');
const cartFooter = document.getElementById('main-cart-footer');

if (cartFooter) cartFooter.classList.toggle('is-empty', parsedState.item_count === 0);
if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty', parsedState.item_count === 0);

this.getSectionsToRender().forEach((section) => {
const elementToReplace =
document.getElementById(section.id).querySelector(section.selector) || document.getElementById(section.id);
elementToReplace.innerHTML = this.getSectionInnerHTML(
parsedState.sections[section.section],
section.selector
);
});
const updatedValue = parsedState.items[line - 1] ? parsedState.items[line - 1].quantity : undefined;
let message = '';
if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) {
if (typeof updatedValue === 'undefined') {
message = window.cartStrings.error;
} else {
message = window.cartStrings.quantityError.replace('[quantity]', updatedValue);

CartPerformance.measure(`${eventTarget}:paint-updated-sections"`, () => {
const parsedState = JSON.parse(state);
const quantityElement =
document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`);
const items = document.querySelectorAll('.cart-item');

if (parsedState.errors) {
quantityElement.value = quantityElement.getAttribute('value');
this.updateLiveRegions(line, parsedState.errors);
return;
}
}
this.updateLiveRegions(line, message);

const lineItem =
document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`);
if (lineItem && lineItem.querySelector(`[name="${name}"]`)) {
cartDrawerWrapper
? trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`))
: lineItem.querySelector(`[name="${name}"]`).focus();
} else if (parsedState.item_count === 0 && cartDrawerWrapper) {
trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'), cartDrawerWrapper.querySelector('a'));
} else if (document.querySelector('.cart-item') && cartDrawerWrapper) {
trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name'));
}

this.classList.toggle('is-empty', parsedState.item_count === 0);
const cartDrawerWrapper = document.querySelector('cart-drawer');
const cartFooter = document.getElementById('main-cart-footer');

if (cartFooter) cartFooter.classList.toggle('is-empty', parsedState.item_count === 0);
if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty', parsedState.item_count === 0);

this.getSectionsToRender().forEach((section) => {
const elementToReplace =
document.getElementById(section.id).querySelector(section.selector) || document.getElementById(section.id);
elementToReplace.innerHTML = this.getSectionInnerHTML(
parsedState.sections[section.section],
section.selector
);
});
const updatedValue = parsedState.items[line - 1] ? parsedState.items[line - 1].quantity : undefined;
let message = '';
if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) {
if (typeof updatedValue === 'undefined') {
message = window.cartStrings.error;
} else {
message = window.cartStrings.quantityError.replace('[quantity]', updatedValue);
}
}
this.updateLiveRegions(line, message);

const lineItem =
document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`);
if (lineItem && lineItem.querySelector(`[name="${name}"]`)) {
cartDrawerWrapper
? trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`))
: lineItem.querySelector(`[name="${name}"]`).focus();
} else if (parsedState.item_count === 0 && cartDrawerWrapper) {
trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'), cartDrawerWrapper.querySelector('a'));
} else if (document.querySelector('.cart-item') && cartDrawerWrapper) {
trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name'));
}
});

CartPerformance.measureFromEvent(`${eventTarget}:click-event`, event);

publish(PUB_SUB_EVENTS.cartUpdate, { source: 'cart-items', cartData: parsedState, variantId: variantId });
})
Expand Down Expand Up @@ -277,7 +284,8 @@ if (!customElements.get('cart-note')) {
'input',
debounce((event) => {
const body = JSON.stringify({ note: event.target.value });
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } });
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } })
.then(() => CartPerformance.measureFromEvent('note-update:click-event', event));
}, ON_CHANGE_DEBOUNCE_TIMER)
);
}
Expand Down
34 changes: 34 additions & 0 deletions assets/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -1267,3 +1267,37 @@ class BulkAdd extends HTMLElement {
if (!customElements.get('bulk-add')) {
customElements.define('bulk-add', BulkAdd);
}

class CartPerformance {
static #metric_prefix = "cart-performance"

static measureFromEvent(benchmarkName, event) {
const metricName = `${CartPerformance.#metric_prefix}:${benchmarkName}`
const startMarker = performance.mark(`${metricName}:start`, {
startTime: event.timeStamp
});

const endMarker = performance.mark(`${metricName}:end`);

performance.measure(
benchmarkName,
`${metricName}:start`,
`${metricName}:end`
);
}

static measure(benchmarkName, callback) {
const metricName = `${CartPerformance.#metric_prefix}:${benchmarkName}`
const startMarker = performance.mark(`${metricName}:start`);

callback();

const endMarker = performance.mark(`${metricName}:end`);

performance.measure(
benchmarkName,
`${metricName}:start`,
`${metricName}:end`
);
}
}
10 changes: 8 additions & 2 deletions assets/product-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,18 @@ if (!customElements.get('product-form')) {
'modalClosed',
() => {
setTimeout(() => {
this.cart.renderContents(response);
CartPerformance.measure("add:click-event:paint-updated-sections", () => {
this.cart.renderContents(response);
});
});
},
{ once: true }
);
quickAddModal.hide(true);
} else {
this.cart.renderContents(response);
CartPerformance.measure("add:click-event:paint-updated-sections", () => {
this.cart.renderContents(response);
});
}
})
.catch((e) => {
Expand All @@ -97,6 +101,8 @@ if (!customElements.get('product-form')) {
if (this.cart && this.cart.classList.contains('is-empty')) this.cart.classList.remove('is-empty');
if (!this.error) this.submitButton.removeAttribute('aria-disabled');
this.querySelector('.loading__spinner').classList.add('hidden');

CartPerformance.measureFromEvent("add:click-event", evt);
});
}

Expand Down

0 comments on commit 5be4190

Please sign in to comment.