Отправка Vuex создает значительные накладные расходы

#vue.js #vuex #s

Вопрос:

Недавно я заметил, что отправка определенного действия занимает намного больше времени, чем следовало бы, поэтому я решил добавить несколько таймеров.

Это код действия:

 // ...
mutations: {
    setPrimary(state, data) {
        state.resources.primary = data
    }
},
// ...
actions: {
    async load({ commit }) {
        const start = performance.now()
        // ...
        const apiResult = await apiClient.get("/")
        const startCommit = performance.now()
        commit("setPrimary", apiResult)
        console.log(`commit finished in ${performance.now() - startCommit} ms`)
        console.log(`action finished in ${performance.now() - start} ms`)
    }
}
 

И код, отправляющий действие:

 const start = performance.now()
await store.dispatch("load")
console.log(`dispatch finished in ${performance.now() - start} ms`)
 

Теперь ожидаемый результат будет заключаться в том, что тайминги довольно близки, но на самом деле все наоборот:

 action finished in 820
dispatch finished in 1365 ms
 

Что для меня довольно запутанно, так как звонки dispatch не должны добавлять такие огромные накладные расходы. До сих пор я понятия не имею, откуда это может взяться.

Редактировать:

Оказывается, это вызвано commit звонком. Задержка не оправдывается и без этого. Время фиксации, подобное этому, показывает, что для выполнения требуется всего 1 мс, а это означает, что у этого каким-то образом есть побочные эффекты, о которых я не знаю.

Комментарии:

1. Активен ли Vue devtools? Можно ли это воспроизвести в производственном режиме? тело функции опущено для краткости — вот в чем проблема с вопросом. Если вы можете воспроизвести его без этого кода, сделайте это. В противном случае это актуально и не должно быть опущено.

2. @EstusFlask Vue devtools активен, но его можно воспроизвести в производственном режиме. Я не понимаю, почему код имеет значение, так как время происходит прямо за пределами dispatch вызова и прямо там, где начинается и заканчивается действие. Не должно быть такой существенной разницы, независимо от того, какой код выполняется между ними, если только с моей стороны не возникнет огромного недопонимания.

3. Vue devtools должен быть неактивен по умолчанию в prod, не так ли? Попробуйте, чтобы Vue devtools были неактивны, чтобы вы были уверены, что они не вызывают замедления. Это важно, потому что неясно, оправдана ли задержка в 800 мс или имеет место какое-то глобальное замедление. Плагины Vuex могут вызвать задержку, или есть какой-то параллельный процесс, который занимает основной поток, включая визуализатор Vue. Я бы не ожидал, что в этом месте из ниоткуда возникнет 550 миль.

4. Я попробовал это с отключенными devtools, результат был похожим (меньшая задержка, но все равно примерно вдвое больше времени для выполнения dispatch . Чего я не могу понять, так это того, как может быть оправдана любая значительная задержка, поскольку оба таймера должны отсчитывать время выполнения действия. Поэтому, если что-то внутри действия происходит медленно, это также должно отображаться в результатах синхронизации внутри действия. Но, похоже, это не так.

5. Я последовал вашему намеку на то, что это может быть что-то внутри действия, и оказывается, что есть определенный commit вызов, который вызывает эту задержку. Но я рассчитал время этого вызова, и он сообщает о времени выполнения всего 1 мс. Если я удалю этот вызов, не будет измеряться существенная задержка. Я все еще не вижу, как вызов функции, который выполняется за 1 мс, может вызвать задержку в 500 мс.

Ответ №1:

Накладные расходы возникают из-за того, что ваше действие является «асинхронной» функцией, что означает, что, когда «интерпретатор» выполняет его, он будет передавать его в «API браузера» для обработки его выполнения вместо того, чтобы выполнять его непосредственно в «Стеке», и ждать его результата, а затем вернет его обратно в «очередь», где «Цикл событий» будет ждать, пока стек опустеет, и вернет его с результатами в стек для продолжения выполнения