对于大型对象,JSON.stringify非常慢

时间:2017-08-04 19:01:03

标签: javascript json performance

我在javascript中有一个非常大的对象(大约10MB)。

当我对它进行字符串化时,它需要很长时间,所以我将它发送到后端并将其解析为一个对象(实际上是带有数组的嵌套对象),这也需要很长时间,但这不是我们在这个问题中的问题。

问题:

如何让JSON.stringify更快,任何想法或替代方案,我需要一个javaScript解决方案,我可以使用的库或想法。

我尝试了什么

我google了很多,看起来没有比JSON.stringify更好的表现,或者我的谷歌搜索技能生锈了!

结果

我接受任何可以解决我在请求中长时间保存(发送到后端)的建议(我知道它的大请求)。

代码问题示例(有关问题的详细信息)

Request URL:http://localhost:8081/systemName/controllerA/update.html;jsessionid=FB3848B6C0F4AD9873EA12DBE61E6008
Request Method:POST
Status Code:200 OK

我发送POST给后端,然后发送到 JAVA

的request.getParameter( “BigPostParameter”)

我读了它以使用

转换为对象
 public boolean fromJSON(String string) {
        if (string != null && !string.isEmpty()) {
            ObjectMapper json = new ObjectMapper();
            DateFormat dateFormat = new SimpleDateFormat(YYYY_MM_DD_T_HH_MM_SS_SSS_Z);
            dateFormat.setTimeZone(TimeZone.getDefault());
            json.setDateFormat(dateFormat);
            json.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            WebObject object;
//            Logger.getLogger("JSON Tracker").log(Level.SEVERE, "Start");
            try {
                object = json.readValue(string, this.getClass());
            } catch (IOException ex) {
                Logger.getLogger(JSON_ERROR).log(Level.SEVERE, "JSON Error: {0}", ex.getMessage());
                return false;
            }
//            Logger.getLogger("JSON Tracker").log(Level.SEVERE, "END");
            return this.setThis(object);
        }
        return false;
    }

赞这个

BigObject someObj = new BigObject();
someObj.fromJSON(request.getParameter("BigPostParameter"))

P.S :仅此一行object = json.readValue(string, this.getClass()); 也非常非常慢。

再次总结

  • 发布时间问题(stringify)JavaScript瓶子缺口。

  • 解析那个字符串化成对象的另一个问题(使用jackson),主要是我将svg标记内容作为样式列在该字符串化对象中,其他列是字符串,int主要是

4 个答案:

答案 0 :(得分:2)

正如评论者所说-无法加快解析速度。

如果担心的是应用程序在进行字符串化/解析时被阻止,则尝试将数据拆分为单独的对象,对其进行严格的字符串化处理,然后组合回一个对象,然后再保存到服务器上。

如果应用程序的加载时间不是问题,则可以尝试在现有应用程序之上进行临时的增量更改。

  • ...正在加载应用程序
  • 加载地图数据
  • 完整复制数据
  • ...结束加载
  • ...应用正常运行
  • ...保存更改时
  • 差异复制并更改数据以获取JSON差异
  • 发送更改(比完整数据小得多)
  • ...在服务器上
  • 将服务器上的JSON差异更改应用于服务器上存储的全部数据
  • 保存更改的数据

我使用json-diff https://github.com/andreyvit/json-diff来计算更改,并且类似物很少。

答案 1 :(得分:0)

解析是一个缓慢的过程。如果要发布10MB的对象,请将其转换为文件,blob或缓冲区。使用formdata而不是application / json和application / x-www-form-urlencoded发送该文件/ blob / buffer。

Reference

An example using express/multer

答案 2 :(得分:0)

解决方案

就像大多数“可重复的”大问题一样,您可以使用异步!

但是,等等,即使异步,JS还是不是单线程的吗?是的……但是您可以使用 Service-Workers 来获取真值通过并行化过程,更快地异步和序列化对象。

一般方法

mainPage.js

//= Functions / Classes =============================================================|
// To tell JSON stringify that this is already processed, don't touch
class SerializedChunk {
  constructor(data){this.data = data}
  toJSON() {return this.data}
}

// Attach all events and props we need on workers to handle this use case
const mapCommonBindings = w => {
  w.addEventListener('message', e => w._res(e.data), false)
  w.addEventListener('error', e => w._rej(e.data), false)
  w.solve = obj => {
    w._state && await w._state.catch(_=>_) // Wait for any older tasks to complete if there is another queued
    w._state = new Promise((_res, _rej) => {
      // Give this object promise bindings that can be handled by the event bindings
      // (just make sure not to fire 2 errors or 2 messages at the same time)
      Object.assign(w, {_res, _rej})
    })
    w.postMessage(obj)
    return await w._state // Return the final output, when we get the `message` event
  }
}

//= Initialization ===================================================================|
// Let's make our 10 workers
const workers = Array(10).fill(0).map(_ => new Worker('worker.js'))
workers.forEach(mapCommonBindings)

// A helper function that schedules workers in a round-robin
workers.schedule = async task => {
  workers._c = ((workers._c || -1) + 1) % workers.length
  const worker = workers[workers._c]
  return await worker.solve(task)
}
// A helper used below that takes an object key, value pair and uses a worker to solve it
const _asyncHandleValuePair = async ([key, value]) => [key, new SerializedChunk(
  await workers.schedule(value)
)]

//= Final Function ===================================================================|
// The new function (You could improve the runtime by changing how this function schedules tasks)
// Note! This is async now, obviously
const jsonStringifyThreaded = async o => {
  const f_pairs = await Promise.all(Object.entries(o).map(_asyncHandleValuePair))

  // Take all final processed pairs, create a new object, JSON stringify top level
  final = f_pairs.reduce((o, ([key, chunk]) => (
    o[key] = chunk,  // Add current key / chunk to object
    o                // Return the object to next reduce
  ), {})             // Seed empty object that will contain all the data
  return JSON.stringify(final)
}

/* lot of other code, till the function that actually uses this code */

async function submitter() {
  // other stuff
  const payload = await jsonStringifyThreaded(input.value)
  await server.send(payload)
  console.log('Done!')
}

worker.js

self.addEventListener('message', function(e) {
  const obj = e.data
  self.postMessage(JSON.stringify(obj))
}, false)

注意:

这可以通过以下方式进行:

  • 创建一个包含10个工人的列表,并向他们添加一些方法和道具
    • 我们关心async .solve(Object): String,它使用承诺解决了我们的任务,同时掩盖了回调地狱
  • 使用新方法:async jsonStringifyThreaded(Object): String,该方法异步执行JSON.stringify
    • 我们将对象分成多个条目并并行求解(可以将其优化为递归到一定深度,请使用最佳判断力:)
    • 已处理的块被转换为SerializedChunk照原样使用的JSON.stringify,而不尝试处理(因为它具有.toJSON()
    • 在内部,如果密钥数超过了工作线程数,我们将循环回到第一个工作线程并对其进行过度调度(请记住,它们可以处理排队的任务)

优化

您可能还需要考虑一些其他事情来提高性能:

  • 使用Transferable Objects,将大大减少将对象传递给服务人员的开销
  • 重新设计jsonStringifyThreaded(),以在更深层次上安排更多对象。

答案 3 :(得分:0)

您可以探索诸如fast-json-stringify之类的库,这些库使用模板架构,并在转换json对象时使用它,以提高性能。检查以下文章。

https://developpaper.com/how-to-improve-the-performance-of-json-stringify/