image

Introduction

Caching is the technique of storing resources and serving them back when requested. When a similar request is made for the second time, cached resources are served instead of fetching resources from server. Cached data are snapshots of the requested resource that expires after a given time. The advantage of caching is that it liberates the server from preforming unnecessary tasks while improving response time.

There are several types of caches these are grouped into two main categories. private or shared caches.

  • Shared cache: The cache is stored for reuse by more than one user.
  • Private cache: The cache is dedicated to a single user.

Real world examples and caching benefits

Lets say for example you visit chekiprice search for “mini pc”. The request is processed by our servers through crawling a couple of stores on the internet. The API then responds back with a bunch of mini pc in Kenya (data includes their prices and stores URLs) but before responding the API does caching for the expensive operation. When the next user located somewhere else makes the same request to the API for “mini pc”. The server responds immediately from cached data and does not crawl stores on the internet. This is what we call shared cache, the cache is shared amongst users. Of courses the cache expires after some time. Otherwise we would serve invalid data.

This is good but not enough to make user web experience seamless.

Now imagine after getting the response from the API the data is rendered to the browser. The user is unsatisfied with the results, edits his/her search to search for “intel mini pc”. The user then decides to go back.

The browser recreates the components all over again and make the API call all over again. However this is an unnecessary request and unnecessary recreating of the components since the data is unchanged. Its always a good idea to minimize the amount of API calls. Not only does minimizing API calls save time but also server resources.

This inefficiency leads to the need for browser caching. This type of caching would immensely reduce API fetch times and components rendering for already rendered components. The cache is privately held and not shared amongst users. This technique of caching is a form of private cache.

API caching

Depending on what language your API written in you can attempt to do the caching by yourself or check if there is an existing plugin for caching. If your option is creating the API by yourself I would recommend using REDIS for caching. However if your using flask there is a great plugin known as Flask-Caching for caching requests. It’s very easy to get started.

Simple flask caching with flask-caching

Installation

pip install Flask-Caching

Sample Code

from flask import Flask

from flask_caching import Cache

config = {

    "DEBUG": True,          # some Flask specific configs

    "CACHE_TYPE": "simple", # Flask-Caching related configs

    "CACHE_DEFAULT_TIMEOUT": 300

}

app = Flask(__name__)

# tell Flask to use the above defined config

app.config.from_mapping(config)

cache = Cache(app)

@app.route("/")

@cache.cached(timeout=10) #cache for 10 seconds

def index():

   random_number = randint(1,100) #generate random number

   return f'Random number: {random_number}'

#run app

if __name__ == '__main__':

 app.run()

Expected behavior: The random number is cached for 10 seconds. When you reload the page before 10 seconds elapse data is fetched from the cache. The random number generator doesn't get executed until 10 seconds are up. In real word this could be an expensive operation.

VUEJS CACHING

Keep-Alive

The keep-alive tag in Vuejs is used for caching component instances once created. This is to avoid re-rendering the component every time. Depending on your use case keep alive can be an advantage or a disadvantage.

Disadvantages of keep alive

  • The use of keep-alive means you lose access lifecycle hooks i.e created, mounted.
  • If rely on building and destroying components you should probably keep away.

Advantage of keep-alive

  • Quicker user switching between pages
  • Components make API call only once
  • Enable ease in storing the scroll position
  • Useful for caching form data.

Keep-alive hooks

To observe switching between cache keep-alive has two unique lifecycle hooks.

  • activated : Called when a kept alive component is activated.
  • deactivated: Called when, you guessed it, a kept alive component is deactivated.

How the keep-alive hooks look like in action:

mounted() {

    console.log('Called when have mount')

},

activated () {

    console.log('Called when have activated')

},

deactivated () {

    console.log('Called when have deactivated')

}

Caching Vuejs routes and keeping scroll position.

In order to cache routes we enclose <router-view></router-view> with keep-alive. We’ll use vue-keep-scroll-position package to assist in remembering the scroll position.

Install vue-keep-scroll-position

npm i -S vue-keep-scroll-position

Add package to Main.js

import Vue from 'vue'

import VueKeepScrollPosition from 'vue-keep-scroll-position'

Vue.use(VueKeepScrollPosition)

Add code for caching routes in App.vue

Assumption: Your using vue router

<keep-alive>

  <router-view v-keep-scroll-position></router-view>

</keep-alive>

And just like that you have implement remembering scroll position and caching on your Vue application.

(Advanced) Caching Vuejs routes and Remember scroll position without a third party package.

You don't need a third party package for vue to recall scroll position. In order to cache routes we just enclose the router- view with keep-alive, this time we dont add v-keep-scroll-position prop.

<keep-alive>

  <router-view></router-view>

</keep-alive>

Remember Vuejs scroll position without third party package.

In order to remember scroll position add the following code in main.js after defining router.

const router = new VueRouter({

  mode: 'history',

  routes

}) //defining router


const scrollableElementId = 'content' // You should change this

const scrollPositions = Object.create(null)


router.beforeEach((to, from, next) => {

  let element = document.getElementById(scrollableElementId)

  if (element !== null) {

    scrollPositions[from.name] = element.scrollTop

  }


  next()

})


window.addEventListener('popstate', () => {

  let currentRouteName = router.history.current.name


  let element = document.getElementById(scrollableElementId)

  if (element !== null && currentRouteName in scrollPositions) {

    setTimeout(() => element.scrollTop = scrollPositions[currentRouteName], 50)

  }

})

And that's it.