Почему не работает проверка на undefined?

В функции getRates в if () есть проверка на undefined, но при попытке запустить код выводит ошибку:

TypeError: Cannot read property 'tm' of undefined

Вот код:

const fetch = require('node-fetch');

let ratesCache = [];

module.exports = async function getRates(path, cacheName) {
    const s = 1000,
        m = s * 60,
        h = m * 60,
        d = h * 24,
        tm = Date.now(),
        findObj = (field) => {
            return ratesCache.find(obj => obj.name === cacheName)[field];
        }

    if (typeof ratesCache[cacheName] !== undefined && findObj('tm') !== undefined && tm - findObj('tm') <= m * 3) {
        return findObj('data');
    }

    const res = await fetch(path),
        data = await res.json();

    ratesCache.push({ name: cacheName, tm, data });

    return data;
}

Пример вызова функции:

await getRates('https://blockchain.info/ru/ticker', 'BTC')

Ответы (1 шт):

Автор решения: nörbörnën

Причина ошибки тут в том, что ratesCache.find может ничего не найти и при этом не выполняется проверка результата find - сразу выполняется доступ по ключу.

Можно исправить так:

findObj = (field) => {
    const o = ratesCache.find(obj => obj.name === cacheName);
    if (o) {
        return o[field];
    }
};

typeof ratesCache[cacheName] != undefined - не верно, typeof всегда вернёт строку. вовсе не нужная проверка. findObj зачем-то трижды вызывается...


Можно написать всё короче и понятнее, через объект/map и любой другой аналог словаря:

const ratesCache = {};
const ratesCacheValid = 3 * 60 * 1000;

module.exports = async function getRates(path, cacheKey = path) {
    const cache = ratesCache[cacheKey];
    const dt = Date.now();
    if (!cache || (dt - cache.dt) > ratesCacheValid) {
        const res = await fetch(path);
        const data = await res.json();
        ratesCache[cacheKey] = { dt, data };
    }
    return ratesCache[cacheKey];
}

ещё правильнее написать всё совсем иначе... ну вот зачем внутри роута знать о том к какому ресурсу обратиться и как называется ключ кэша... роут должен передать управление "сервису" в котором эти данные изолированы, ну и т.д.

→ Ссылка