简体   繁体   English

如何处理从 API 获取的大量数据

[英]How to handle a lot of data fetching from API

I am a beginner.我是初学者。 I am trying to get data from an API and list them by using v-for .我正在尝试从 API 获取数据并使用v-for列出它们。 But It is causing a lag.但它造成了滞后。 My app is freezing when data comes or when I search for something on my list.当数据到来或当我搜索列表中的内容时,我的应用程序冻结。 This part of the code is where I fetch data.这部分代码是我获取数据的地方。 How to improve that code to have a more fluent app.如何改进该代码以获得更流畅的应用程序。

async created() {
    this.loaded = false;

    try {
      const response = await fetch(
        'https://api2.binance.com/api/v3/ticker/24hr'
      );
      const data = await response.json();
      data.forEach(element => {
        this.chartData.symbols = [...this.chartData.symbols, element.symbol];
        this.chartData.price = [...this.chartData.price, +element.lastPrice];
      });

      this.loaded = true;
    } catch (e) {
      console.error(e);
    }
  },

My App component:我的应用组件:

<template>
  <v-app>
    <v-row align="center" class="ma-8 pa-6" fluid>
      <!-- Container Start Point For buttons-->
      <div class="mb-6 d-flex justify-start hidden">
        <v-btn @click="toggleButton" depressed color="primary" class="mr-6 btn">
          {{ (btnText = dialog ? 'Add/Update' : 'Add Stock') }}
        </v-btn>

        <v-btn @click="refreshPage" depressed color="primary" class="btn">
          Refresh
        </v-btn>
      </div>
      <!-- Container End Point For Buttons-->

      <!-- Modal Code Starts-->
      <v-dialog
        v-model="dialog"
        width="80%"
        height="900px"
        overflow="hidden"
        pa-6
      >
        <v-card class="pa-12">
          <v-form>
            <v-text-field
              v-model="search"
              label="Search"
              outlined
            ></v-text-field>

            <v-row>
              <v-list-item
                v-for="(pair, index) in filterBy(pairs, search)"
                :key="pair.symbol"
              >
                <v-list-item-content>
                  <v-list-item-title ref="refWord"
                    >{{ pair.symbol }} - {{ pair.price }}</v-list-item-title
                  >
                </v-list-item-content>
                <v-text-field
                  outlined
                  v-model="numberValue"
                  hide-details
                  single-line
                  type="number"
                  class="shrink mr-2"
                  width="50px"
                  height="50px"
                />
                <AddBtn @click-event="searchHandle(index)" />
              </v-list-item>
            </v-row>
          </v-form>
        </v-card>
      </v-dialog>
      <!-- Modal Code Ends-->

      <!-- Horizontal Line-->
      <hr class="line" />

      <!--Mainpage List Starts -->
      <v-col cols="12" sm="5" height="1000px">
        <v-container height="1000px">
          <v-list-item
            class="border"
            v-for="(label, index) in chartData.labels"
            :key="index++"
          >
            <v-row>
              <v-list-item-content d-flex>
                <v-list-item-title
                  >{{ label }}
                  <span>{{
                    chartData.datasets[0].data[index]
                  }}</span></v-list-item-title
                >
              </v-list-item-content>
              <v-btn class="btn" dark md color="error" @click="deleteHandle">
                Delete
              </v-btn>
            </v-row>
          </v-list-item>
        </v-container>
      </v-col>
      <!-- Mainpage List  End-->

      <!-- Vertical Line-->

      <hr class="vertical" />

      <!-- Chart part -->
      <v-col cols="12" sm="5">
        <PieChart
          :data="this.chartData.datasets[0].data"
          :bgColor="this.chartData.datasets[0].backgroundColor"
          :labels="this.chartData.labels"
          :key="this.chartData.labels.length"
        />
      </v-col>
      <!-- Chart part end-->
    </v-row>
  </v-app>
</template>

<script>
import PieChart from './components/PieChart';
import Vue2Filters from 'vue2-filters';
import AddBtn from './components/AddBtn.vue';

export default {
  name: 'App',
  mixins: [Vue2Filters.mixin],

  components: {PieChart, AddBtn},
  methods: {
    toggleButton() {
      this.dialog = !this.dialog;
      // this.btnText = this.dialog ? 'Add / Update' : 'Add Stock';
    },
    searchHandle(index) {
      const [sym, price] = this.$refs.refWord[index].innerText.split('-');
      this.symbol = sym;
      this.chartData.labels = [...this.chartData.labels, sym];
      this.chartData.datasets[0].data = [
        ...this.chartData.datasets[0].data,
        +price,
      ];
    },
    deleteHandle() {
      this.chartData.labels.pop();
      this.chartData.datasets[0].data.pop();
      this.chartData.datasets[0].backgroundColor.pop();
    },
    refreshPage() {
      setTimeout(function () {
        location.reload();
      }, 100);
    },
  },

  data: () => ({
    dialog: false,
    search: '',
    btnText: 'Add Stock',
    numberValue: 1,
    chartData: {
      labels: ['CHM', 'BBM', 'LLJTRY'],
      symbols: [],
      price: [],
      datasets: [
        {
          data: [0.035, 0.26, 0.022],
          backgroundColor: [
            '#41B883',
            '#E46651',
            '#20AB2E',
            '#DD1B16',
            '#DD26FF',
            '#9ab973',
            `#${Math.floor(Math.random() * 16777215).toString(16)}`, // Random color
          ],
        },
      ],
    },
  }),
  computed: {
    pairs() {
      return this.chartData.symbols.map((symbol, i) => {
        return {
          symbol: symbol,
          price: this.chartData.price[i],
        };
      });
    },
  },
  async created() {
    this.loaded = false;

    try {
      const response = await fetch(
        'https://api2.binance.com/api/v3/ticker/24hr'
      );
      const data = await response.json();
      data.forEach(element => {
        this.chartData.symbols = [...this.chartData.symbols, element.symbol];
        this.chartData.price = [...this.chartData.price, +element.lastPrice];
      });

      this.loaded = true;
    } catch (e) {
      console.error(e);
    }
  },
};
</script>

<style scoped>
.btn {
  text-transform: none !important;
}
.line {
  width: 100%;
  margin: 0 auto;
}
hr.vertical {
  height: 80%;
  margin: 3% auto;
}
.scroller {
  height: 100%;
}
.border {
  border: 1px solid rgba(0, 0, 0, 0.123);
  padding: 5px 20px;
  margin: 10px 0;
  border-radius: 10px;
}
</style>

PieChart Component:饼图组件:

<template>
  <Pie
    v-if="loaded && this.chartData.labels.length !== 0"
    id="my-chart-id"
    :options="chartOptions"
    :data="chartData"
  />
  <Pie v-else :options="chartOptions" :data="emptyChartData"></Pie>
</template>

<script>
import {Chart as ChartJS, ArcElement, Tooltip, Legend} from 'chart.js';
import {Pie} from 'vue-chartjs';

ChartJS.register(ArcElement, Tooltip, Legend);

export default {
  name: 'PieChart',
  components: {Pie},
  props: ['data', 'bgColor', 'labels'],
  data() {
    return {
      chartData: {
        labels: [...this.labels],
        datasets: [
          {
            data: [...this.data],
            backgroundColor: [...this.bgColor],
          },
        ],
      },
      emptyChartData: {
        labels: [],
        datasets: [
          {
            data: [0.01],
            backgroundColor: ['#999797'],
          },
        ],
      },
      chartOptions: {
        responsive: true,
        elements: {
          arc: {
            borderWidth: 0,
          },
        },
      },
      loaded: true,
    };
  },
};
</script>

AddBtn component:添加按钮组件:

<template>
  <v-btn class="btn" dark md color="success" @click="$emit('click-event')">
    Add
  </v-btn>
</template>

<script>
export default {};
</script>

<style></style>

I list API coming data by using v-for.我使用 v-for 列出了 API 即将到来的数据。

<v-row>
              <v-list-item
                v-for="(pair, index) in filterBy(pairs, search)"
                :key="pair.symbol"
              >
                <v-list-item-content>
                  <v-list-item-title ref="refWord"
                    >{{ pair.symbol }} - {{ pair.price }}</v-list-item-title
                  >
                </v-list-item-content>
                <v-text-field
                  outlined
                  v-model="numberValue"
                  hide-details
                  single-line
                  type="number"
                  class="shrink mr-2"
                  width="50px"
                  height="50px"
                />
                <AddBtn @click-event="searchHandle(index)" />
              </v-list-item>
            </v-row>
          </v-form>
        </v-card>
      </v-dialog>

I think your problem comes from the overuse of the spread syntax ( ... ).我认为您的问题来自过度使用传播语法( ... )。 This is a nice ES6 feature, but you should be very careful when you use it within a loop.这是一个很好的 ES6 特性,但是在循环中使用它时应该非常小心。

The API you are working with returns more than 2,000 entries and, for each iteration, you are spreading two arrays which are incrementally more complex.您正在使用的 API 返回超过 2,000 个条目,并且对于每次迭代,您正在传播两个 arrays,它们逐渐变得更加复杂。 This is absolutely not necessary and, of course, it is terrible in terms of performance.这绝对没有必要,当然,就性能而言,这很糟糕。

I suggest you to use Array.prototype.push() .我建议你使用Array.prototype.push()

A simple test using JSBench.Me shows a huge difference between these two strategies:使用JSBench.Me的简单测试显示了这两种策略之间的巨大差异:

传播与推动

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM