Как можно улучшить/оптимизировать код node.js?

Нужна помощь по оптимизации кода на node.js. Сейчас он довольно "ужасный", хотел бы узнать совет специалистов, где можно улучшить.

Ссылка: plnkr.co/edit/EpZ8qDecDIuJ6Xdb?open=lib%2Fscript.js

const cron = require('node-cron')
const Platform = require('../db/models')
const UpDown = require('../db/models/platform/easy/upDown')
const User = require('../db/models/user')
class Easy {
  constructor(name, balance, nameTranslate, data, activeDeals, history, watchPeople, maxDataLength, min, max) {
    this.name = name
    this.title= '1:2'
    this.coefficient = 2
    this.balancePlatform = balance // общий баланс игры
    this.data = {
        name: nameTranslate,
        data: data, //данные, которые меняются каждую секунду
        activeDeals: activeDeals, //данные, от которых зависит изменение свойства каждую секунду
        history: [],
        watchPeople: watchPeople, // кол-во посетителей в данный момент 
        maxDataLength: maxDataLength, // максимальное количество данных в data.data
        min: min, // минимальный Y
        max: max, // максимальный Y
        dataLength: 0,
        rate: 2 // коэфициент
      }
  } //

    /* getters */
    get firstSide() { //первая сторона
      return this.searchSides(true)
    }

    get firstSideNumberUsers() { // подсчет юзеров на одну сторону
      return this.searchSidesNumberUsers(true)
    }

    get lastSide() { // вторая сторона
      return this.searchSides(false)
    }

    get lastSideNumberUsers() {
      return this.searchSidesNumberUsers(false)
    }

    get statusPlatform() {
      if (this.firstSideNumberUsers && this.lastSideNumberUsers) {
        return 'online'
      }

      if (
        (this.firstSideNumberUsers > 0 && this.lastSideNumberUsers === 0)
        ||
        (this.firstSideNumberUsers === 0 && this.lastSideNumberUsers > 0)
      ) {
        return 'platform'
      }

      if (this.firstSideNumberUsers === 0 && this.lastSideNumberUsers === 0) {
        return 'offline'
      }
    }

    get sideStatus() {
      if (this.statusPlatform === 'online') {
        //ищем где сумма выше
        if (this.firstSide > this.lastSide && this.firstSide != this.lastSide) {
          return true
        } else if (this.firstSide < this.lastSide && this.firstSide != this.lastSide) {
          return false
        } else {
          return true
        }
      }
    }

    get returnData() {
      return {
        data: this.data.data, // массив данных, числа
        activeDeals: this.data.activeDeals, // активные сделки
        history: this.data.history, // история за весь день
        watchPeople: this.data.watchPeople, // кол-во посетителей в данный момент
        maxDataLength: this.data.maxDataLength,
        min: this.data.min, // минимальный Y
        max: this.data.max, // максимальный Y
        dataLength: this.data.data.length
      }
    }

    get searchSidesSum() { // количество суммы
      if (this.data.activeDeals.length) {
        return this.data.activeDeals.map(item => {
          return item.sum
        }).reduce((sum, item) => {
          return sum + item
        })
      } else {
        return 0
      }
    }

    /* methods */
    searchSides(dealType) { // количество суммы на сторону
      return this.data.activeDeals.filter(item => {
        return item.dealType === dealType
      }).map(item => {
        return item.sum
      }).reduce((sum, item) => {
        return sum + item
      })
    }

    searchSidesNumberUsers(dealType) { //количество юзеров на сторону
      return this.data.activeDeals.filter(item => {
        return item.dealType === dealType
      }).length
    }

    sortAsc(prev, next) {
      return next.xOpen - prev.xOpen
    }

    sortDesc(prev, next) {
      return prev.xOpen - next.xOpen
    }

    /* actions */
    actionChart(min, max) { /* static logic */
      let lastData = this.data.data[this.data.data.length - 1]
      let generatedNumber = lastData + Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 5)

      if (generatedNumber >= max) {
        generatedNumber = lastData + Math.round(-1 * Math.random() * 5)

        if (generatedNumber >= max) {
          generatedNumber = max
        }
      }

      if (generatedNumber <= min) {
        generatedNumber = lastData + Math.round(1 * Math.random() * 5)
        if (generatedNumber <= min) {
          generatedNumber = min
        }
      }

      if (generatedNumber >= max) {
        generatedNumber = max
      }

      if (generatedNumber <= min) {
        generatedNumber = min
      }

      this.data.data.push(+generatedNumber)

      if (this.data.data.length > this.data.maxDataLength) {
        this.data.data.splice(0, 1)
      }

      this.dataLength = this.data.data.length
      // console.log(min, max)
    }

    actionChartPlatformOnline() {
      if (this.searchSidesSum <= this.balancePlatform) {
        this.actionChart(this.data.min, this.data.max)
      } else {
        let statusSearch = this.data.activeDeals.map(item => {
          return item.dealType
        })

        let status = [...new Set(statusSearch)][0]

        let mainCoords = 0
        let sortUsers = []

        let users = this.data.activeDeals.filter(item => {
          return item.dealType === status
        })

        if (!status) {
          sortUsers = users.sort(this.sortAsc)[0]
        } else {
          sortUsers = users.sort(this.sortDesc)[0]
        }

        mainCoords = sortUsers.xOpen

        if (!status) {
          this.actionChart(mainCoords + 1, this.data.max)
        } else {
          this.actionChart(this.data.min, mainCoords - 1)
        }
      }
    }

    actionChartOffline() { /* complete */
      if (this.statusPlatform === 'offline') {
        this.actionChart(this.data.min, this.data.max)
      }
    }

    actionChartOnlineUpDown() { /* complete */
      if (this.statusPlatform === 'online') {
        this.actionChartPlatformOnline()
      }
    }

    actionChartPlatform() { /* complete */
      if (this.statusPlatform === 'platform') {
        this.actionChartPlatformOnline()
      }
    }

    action() {
      this.actionChartOffline()
      this.actionChartOnlineUpDown()
      this.actionChartPlatform()
    }
  }

// Вот тут самое непонятное в улучшении производительности
// инициализируем класс игры с начальными данными

let modelUpDown = new Easy(
  'upDown',
  0,
  'Выше/ниже',
  [],
  [],
  [],
  0,
  0,
  0,
  0,
  0
)


let actionCompute = () => { // функция, которая запускается каждую секунду..
  Platform.findOne({}, (errBal, resBal) => { // поиск данных платформы (раз запрос)
    UpDown.findOne({}, (err, res) => { // поиск игры (два запрос)
      let chart = res.dataData

      if (!res.dataData.length) chart = [+(res.dataMax / 2)]

      modelUpDown.name = 'upDown'
      modelUpDown.balancePlatform = resBal.balance

      modelUpDown.data.name = 'Trade'
      modelUpDown.data.data = chart
      modelUpDown.data.activeDeals = res.dataActiveDeals //kill
      modelUpDown.data.history = res.dataHistory //kill done
      modelUpDown.data.watchPeople = res.dataWatchPeople
      modelUpDown.data.maxDataLength = res.dataMaxDataLength
      modelUpDown.data.max = res.dataMax
      modelUpDown.data.min = res.dataMin
      modelUpDown.data.dataLength = res.dataLength
      // перезаписываем класс на данные и БД
      //запускаем игру
      modelUpDown.action()

      // продумываем действия для игры
      let addToBaseData = modelUpDown.returnData

      let activeDeals = addToBaseData.activeDeals //берем актуальные данные

      activeDeals.forEach((item, i) => { //ставим статусы
        item.disable = false
        item.xClose = addToBaseData.data[addToBaseData.data.length - 1]

        if (item.dealType) { //если вверх
          if (item.xClose > item.xOpen) {
            item.status = true
          } else {
            item.status = false
          }
        } else {
          if (item.xClose < item.xOpen) {
            item.status = true
          } else {
            item.status = false
          }
        }

        if (new Date() >= new Date(item.dealClose)) {
          item.disable = true
        }
      })

      let notActivities = activeDeals.filter(item => {
        return item.disable
      })

      let activities = activeDeals.filter(item => {
        return !item.disable
      })

      let buildNotActivities = res.dataHistory.concat(notActivities)

      //ищем юзеров, которые учавствуют в игре и отдаем данные в их аккаунт
      if (notActivities.length) {
        notActivities.forEach((item, i) => {
          User.updateOne( //3 запрос
            { id: item.id },
            {
              $push: {
                dealsHistory: {
                  name: 'Trade',
                  idDeal: item.idDeal,
                  dealOpen: item.dealOpen,
                  dealClose: item.dealClose,
                  xOpen: item.xOpen,
                  xClose: item.xClose,
                  sum: item.sum,
                  status: item.status,
                  dealType: item.dealType
                }
              },
              $inc: {
                balance: (item.status) ? item.sum * 2 : 0
              }
            },
            () => {})
        })
      }

     //перезаписываем базу данных игры на новые данные

      let app = UpDown.updateOne( //4 запрос
        { name: 'upDown', title: '1:2' },
        {
          $set:
          {
            dataData: addToBaseData.data,
            dataActiveDeals: activities,
            dataNotActivities: notActivities,
            dataHistory: [],
            dataWatchPeople: addToBaseData.watchPeople,
            dataMaxDataLength: addToBaseData.maxDataLength,
            dataMin: addToBaseData.min,
            dataMax: addToBaseData.max,
            dataLength: addToBaseData.dataLength
          }
        },
        {
          multi: true
        },
        (err, res) => {
          if (err) return false
        }
      )
    })
  })
}

const app = cron.schedule('*/1 * * * * *', () => {
  //запуск функции каждую секунду
  actionCompute()
})

module.exports = app

В общем, понимаю, что максимально неправильно делать 4 запроса в бд + обработать и всё это за одну секунду. Можете что-нибудь посоветовать, как это исправить? потому что при добавлении новых данных начинает всё лагать, что не удивительно. Делать действие каждую секунду нужно обязательно, но может есть другой вариант помимо cron? от setTimeout всё с ума сходит.

Буду благодарен за любой совет и помощь!


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