Pull to refresh

Comments 20

каким образом?
в данном случае через плагин происходит явное записывание axios в контекст приложения, который создан 1 раз. Везде использовать import axios from 'axios' может не совсем подходить из-за того, что может быть конфиг какой нибудь типа кеширования запросов или общие заголовки, и делать это каждый раз не совсем хорошо
ниже ответили за меня. @nuxtjs/axios модуль
Можно попробовать, одно из решений данной проблемы
Ваше решение в статье стоит заменить на указанное выше и вы сами описали одну из причин:
при eject'е этого интерцептора, все запросы кроме первого не пройдут через него

Сама проблема — классический способ выстрелить себе в ногу с node.js, nuxt тут не причем
Не всегда является возможным быстро заменить в проекте axios на nuxt'овый, особенно, когда до конца не уверен что дело в этом, идея статьи помочь тем, кто столкнулся с этой проблемой, и есть надежда, что он прочитает эту статью и выберет любое решение приведенное в ней или в комментарии.
Прочитайте комментарий внимательно, не обязательно заменять модуль:

Сразу оговорюсь, что axios создавался так:
import baseAxios from 'axios';
export default function createAxiosInstance () {
  return baseAxios.create({
    timeout: 10000,
  });
};

А привязывался к контексту приложения вот так:
import createAxiosInstance from './index';
export default function(context) {
    context.axios = createAxiosInstance();
}

только что попробовал сделать таким образом и действительно оно помогло, но есть 1 нюанс, если использовать плагин кеширования, то ничего кешироваться не будет
import baseAxios from 'axios';
import LRUCache from 'lru-cache';

import { cacheAdapterEnhancer } from 'axios-extensions';


export default function () {
  return baseAxios.create({
    timeout: 10000,
    adapter: cacheAdapterEnhancer(baseAxios.defaults.adapter, {
      defaultCache: new LRUCache({
        maxAge: 1000 * 60 * 5,
        max: 50,
      }),
      enabledByDefault: true,
      cacheFlag: 'useCache',
    }),
  });
}

это нужно если я например не хочу каждый раз ходить на апи для получения какой нибудь статической информации, которая меняется не чаще чем раз в час
Ну ё.
Инстанцирование объекта LRUCache вынесите за скобки функции-фабрики
Конечно не будет. Ведь инстанс создаётся на каждый ssr-запрос.
А плагин расчитан на работу с синглтоном, например в браузерном spa.
Т.е. ваш кэш будет работать в рамках одного ssr-контекста, но этого не достаточно, судя по вашей задаче.

В текущей ситуации можно написать какой-то внешний кэшер (под внешним я подразумеваю тот, который будет инстанцироваться как синглтон, на всё приложение). Но здесь в ключе кеша, помимо урла, надо учесть заголовки (ведь для разных зарегистрированных пользователей могут прилететь разные ответы) — Cookie, Pragma, Cache-Control и т.п., параметры запроса — body, query. Также кэшировать можно только GET-запросы, но не POST/PUT/PATCH/DELETE.
А в итоге всё-равно прийти к выводу, что лучше над всем этим вообще не заморачиваться)
Гораздо проще где-то в request-интерцепторе точечно по урлу отлавливать нужные запросы (результат которых нужно закешировать): если в кеше есть результат — сразу его возвращать; если нет — дальше в response-интерцепторе также точечно поймать ответ и положить его в кэш.
Ну или как сказали выше, да) вынести инстанцирование кэша за функцию-фабрику

Написать такую большую статью и так и не разобраться в чём суть и свалить всё на интерцепторы — so frontend way in 2020…
Когдаж вы начнёте основы своих инструментов знать…

Очевидно что суть в замыкании, garbage collector не мог за собой память почистить, потому что компоненты вью ссылались на data, которую вернул axios, и когда он прошел через интерцептор, осталась ссылка интерцептора на data, и поэтому gc ничего не почистил за собой. Когда я столкнулся с этой проблемой, я и понятия не имел что дело в этом, а статья написана в помощь тем, кто столкнется с данной проблемой и чтобы проверили у себя в проекте этот кейс, описанный в статье. В любом случае спасибо за комментарий
Дело не в garbage collector'е (с т.з. gc здесь вообще никакой проблемы нет и очищать ему тут нечего, потому что интерцепторы — это просто массив функций).
А в том, что сам nuxt вызывает все функции-плагины для каждого ssr-запроса (которые объявлены в массиве plugins конфига нюкста), в каждую из которых он передаёт уникальный контекст этого запроса.
А т.к. у вас один инстанс axios'а на всё приложение, то при каждом ssr-запросе к этому синглтону бесконечно добавлялись интерцепторы, до тех пор, пока процессу памяти хватало.
Я дебажил память и видел, что там находятся Vue'ые элементы, да и держать в памяти 10к функций это не сильно ресурсозатратно, я проводил тесты, на которых рендерелись тяжелые страницы, и в этом случае нода падала через 20-40 запросов, а когда рендерилась легкая страница, то могла упасть на 1000ом, в обоих случаях память не вычищалась.
Тут все пытаются объяснить, что у вас логически неверный код и вы описываете его следствия аж на целую статью как открытие. Вы создаете объект для всего приложения, а потом в каждом запросе добавляете ему интерсепторы. Тут нужно или создавать объект для каждого запроса, или интерсепторы прописывать один раз.
Действительно, вся проблема в логически неверном коде, но когда на большом проекте появляются утечки, то не всегда очевидно где их искать. Очень здорово, что появились более красивые решения, чем мои костыли. Цель статьи помочь тем, кто пытается найти утечку памяти у себя.
Обновил статью, добавил решение №0. Всем спасибо.
Sign up to leave a comment.

Articles