【发布时间】:2018-03-20 16:07:48
【问题描述】:
我看到 JSON.stringify 和 JSON.parse 都是同步的。
我想知道是否有一个简单的 npm 库以异步方式执行此操作。
谢谢
【问题讨论】:
-
从源头来看,这个库似乎没有做任何异步操作。 JSON.parse 在主线程中并且确实阻塞了事件循环。
-
Javascript 不是多线程的......它只是交换执行机会
我看到 JSON.stringify 和 JSON.parse 都是同步的。
我想知道是否有一个简单的 npm 库以异步方式执行此操作。
谢谢
【问题讨论】:
您可以使用 Promises 使任何东西“异步”:
function asyncStringify(str) {
return new Promise((resolve, reject) => {
resolve(JSON.stringify(str));
});
}
然后你可以像使用任何其他承诺一样使用它:
asyncStringfy(str).then(ajaxSubmit);
请注意,由于代码不是异步的,因此 promise 将立即被解析(对 JSON 进行字符串化没有阻塞操作,不需要任何系统调用)。
如果您的平台支持,您也可以使用 async/await API:
async function asyncStringify(str) {
return JSON.stringify(str);
}
那么你就可以用同样的方式来使用它了:
asyncStringfy(str).then(ajaxSubmit);
// or use the "await" API
const strJson = await asyncStringify(str);
ajaxSubmit(strJson);
已编辑: 添加真正的异步解析/字符串化(可能是因为我们解析的东西太复杂)的一种方法是将作业传递给另一个进程(或服务)并等待响应。
您可以通过多种方式做到这一点(比如创建一个共享 REST API 的新服务),我将在这里演示一种通过进程之间的消息传递来做到这一点的方法:
首先创建一个负责解析/字符串化的文件。为了示例,将其称为 async-json.js:
// async-json.js
function stringify(value) {
return JSON.stringify(value);
}
function parse(value) {
return JSON.parse(value);
}
process.on('message', function(message) {
let result;
if (message.method === 'stringify') {
result = stringify(message.value)
} else if (message.method === 'parse') {
result = parse(message.value);
}
process.send({ callerId: message.callerId, returnValue: result });
});
这个过程所做的就是等待一条消息,要求对 JSON 进行字符串化或解析,然后以正确的值进行响应。 现在,在您的代码上,您可以分叉此脚本并来回发送消息。每当发送请求时,您都会创建一个新的 Promise,每当响应返回到该请求时,您就可以解决该 Promise:
const fork = require('child_process').fork;
const asyncJson = fork(__dirname + '/async-json.js');
const callers = {};
asyncJson.on('message', function(response) {
callers[response.callerId].resolve(response.returnValue);
});
function callAsyncJson(method, value) {
const callerId = parseInt(Math.random() * 1000000);
const callPromise = new Promise((resolve, reject) => {
callers[callerId] = { resolve: resolve, reject: reject };
asyncJson.send({ callerId: callerId, method: method, value: value });
});
return callPromise;
}
function JsonStringify(value) {
return callAsyncJson('stringify', value);
}
function JsonParse(value) {
return callAsyncJson('parse', value);
}
JsonStringify({ a: 1 }).then(console.log.bind(console));
JsonParse('{ "a": "1" }').then(console.log.bind(console));
注意:这只是一个例子,但是知道了这一点,您可以找出其他改进或其他方法来做到这一点。希望这会有所帮助。
【讨论】:
stringify 更改为parse。
stringify 是一种“全内存算法”,它不执行任何系统调用,它永远不会阻塞事件循环。如果您确实需要异步完成或解释目标,您可以使用流程和消息传递,并且可能会更简单的解决方案(稍后我将使用真正的异步编辑我的响应)
看看这个,另一个 npm 包-
async-json is a library that provides an asynchronous version of the standard JSON.stringify.
安装-
npm install async-json
例子-
var asyncJSON = require('async-json');
asyncJSON.stringify({ some: "data" }, function (err, jsonValue) {
if (err) {
throw err;
}
jsonValue === '{"some":"data"}';
});
注意-没有测试,你需要手动检查它的依赖和 所需的软件包。
【讨论】:
异步我假设您实际上是指非阻塞异步 - 即,如果您有一个大(兆字节大)的 JSON 字符串,并且您进行字符串化,那么您不会'不希望您的 Web 服务器在处理对象时硬冻结和阻止新传入的 Web 请求 500 多毫秒。
一般的答案是逐个迭代您的对象,然后在达到阈值时调用setImmedate。然后,这允许事件队列中的其他函数运行一段时间。
对于 JSON(反)序列化,yieldable-json 库做得很好。然而,它确实极大地牺牲了 JSON 处理时间(这在某种程度上是故意的)。
用法:
const yj = require('yieldable-json')
yj.stringifyAsync({key:"value"}, (err, data) => {
if (!err)
console.log(data)
})
如果处理速度非常重要(例如处理实时数据),您可能需要考虑生成多个 Node 线程。我使用PM2 Process Manager 取得了巨大的成功,尽管初始设置非常艰巨。然而,一旦它起作用,最终的结果是神奇的,不需要修改你的源代码,只需要修改你的 package.json 文件。它充当 Node 应用程序的代理、负载平衡器和监控工具。它有点类似于 Docker swarm,但是是裸机,并且不需要服务器上的特殊客户端。
【讨论】: