Как проанализировать большой внешний файл json, хранящийся локально (~ 30 МБ), чтобы заполнить выпадающий список выбора, избегая длительного времени загрузки? - PullRequest
0 голосов
/ 09 ноября 2019

Я пытаюсь проанализировать файл JSON, содержащий около 209 579 объектов (размер файла ~ 30 МБ), и заполнить их (имена и атрибуты значений) в раскрывающемся меню с помощью тегов select-option. Я мог бы проанализировать весь файл, используя метод jquery getJSON, чтобы проанализировать и заполнить его традиционным способом нацеливания на элемент DOM, но когда я выбираю раскрывающееся меню, это занимает слишком много времени для отображения содержимого и отключает браузер на этот период времени.

Я пробовал с меньшим набором данных с ~ 100 объектами (что значительно меньше), и страница быстро отображает выпадающий список и не задерживается. Вот почему я думаю, что у меня проблема из-за моего большого набора данных объекта JSON.

<!--html code-->
<h3>Select your Location:</h3>
<select id="locality-dropdown" name="locality">
</select>

//referenced from https://www.codebyamir.com/blog/populate-a-select-dropdown-list-with-json 
//(I have used the same technique)

let dropdown = document.getElementById('locality-dropdown');
dropdown.length = 0;

let defaultOption = document.createElement('option');
defaultOption.text = 'Choose State/Province';

dropdown.add(defaultOption);
dropdown.selectedIndex = 0;

const url = 'js/city_list1.json';

fetch(url)  
  .then(  
    function(response) {  
      if (response.status !== 200) {  
        console.warn('Looks like there was a problem. Status Code: ' + 
          response.status);  
        return;  
      }

      // Examine the text in the response  
      response.json().then(function(data) {  
        let option;

        for (let i = 0; i < data.length; i++) {
          option = document.createElement('option');
          option.text = data[i].name;
          option.value = data[i].id;
          dropdown.add(option);
        }    
      });  
    }  
  )  
  .catch(function(err) {  
    console.error('Fetch Error -', err);  
  });

Я ожидаю, что выпадающий будет, как на обычных сайтах, но в моем случае браузер перестает отвечатьи требуется некоторое время для загрузки содержимого в раскрывающемся меню, когда я нажимаю на раскрывающееся меню.

Ответы [ 3 ]

2 голосов
/ 09 ноября 2019

Как вы правильно заметили, узким местом в вашем случае является тот факт, что вы пытаетесь загрузить весь набор данных одновременно. Вместо этого вам следует рассмотреть возможность загрузки этих данных в страницы (порции) и, возможно, иметь оконный компонент, который загружает / отображает только те данные, которые отображаются в данный момент.

Как отметили другие, JSON - не лучший формат для хранения огромных наборов данных. база данных намного лучше, даже что-то простое и маленькое, как SQLite .

Но если вы все же предпочитаете продолжить работу с JSON, я бы порекомендовал попробовать одну из библиотек, которая позволяет вам анализировать частичные блоки JSON и несколько имитировать то, что было бы, если бы вы использовали базу данных и загрузку данных с разбивкой по страницам.

Например, stream-json (Модуль NodeJS, но я думаю, что можно легко найти что-то похожее для любой технологии бэкенда).

stream-json - это микробиблиотека потока node.jsКомпоненты с минимальными зависимостями для создания пользовательских процессоров данных, ориентированных на обработку огромных файлов JSON при минимальных затратах памяти. Он может анализировать файлы JSON, значительно превышающие доступную память. Даже отдельные примитивные элементы данных (ключи, строки и числа) могут передаваться поэтапно.

const { chain } = require('stream-chain')

const { parser } = require('stream-json')
const { pick } = require('stream-json/filters/Pick')
const { streamValues } = require('stream-json/streamers/StreamValues')

const fs = require('fs')

const pipeline = chain([
  fs.createReadStream('sample.json'),
  parser(),
  pick({ filter: 'data' }),
  streamValues(),
  data => {
    const value = data.value
    return value && value.department === 'accounting' ? data : null
  }
])

let counter = 0
pipeline.on('data', () => ++counter)
pipeline.on('end', () =>
  console.log(`The accounting department has ${counter} employees.`)
)
2 голосов
/ 09 ноября 2019

«Нормальные сайты» не имеют поля выбора с опциями 209,579. Скорость здесь не будет зависеть от вашего кода, но в основном от производительности клиентского компьютера и скорости соединения. Здесь вы должны подумать об альтернативах, таких как функция автозаполнения или, возможно, бесконечная прокрутка, и тому подобное.

1 голос
/ 09 ноября 2019

Вы не можете ожидать, что загрузка 200000 записей в браузер будет производительной в этом сценарии и будет ужасным опытом для пользователей - конечно, это должно быть очевидно. Вам нужно будет сохранить данные в БД или, возможно, массив в браузере, а затем искать эти данные и возвращать только те строки, которые соответствуют автозаполнению, а затем добавлять их в таблицу / таблицу, чтобы ограничить результаты. Раскрывающийся список для такого количества данных звучит как проблема.

Как еще один старый совет, скорее соберите данные опций в строку и добавьте их в dom один раз вместо 100 раз, используя creatElement.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...