我正在研究 Swagger Editor 的性能。提升性能的一个途径就是将任务繁重的线程交给Web Workers。Web Workers确实在处理(如何)从主线程中移除任务繁重的线程等方面表现的很好,但是我们和Web Workers之间的线程通信是非常缓慢的。对于需要发送的每条信息或者从Web Workers中的一个线程接收到的信息,我们都需要将它转换成字符串。这就意味着,在主线程和worker线程之间需要使用JSON.parse来转换对象,然后使用JSON.stringify来实现我们的对象的向上以及向下兼容。
对于比较大的对象来说,这可能导致阻塞式JSON.parse方法的调用。例如,当对象从我们的AST-composer worker转换回AST时,我发现出现50ms的阻塞。50ms的暂停可以轻易使4个窗口终止运行。
虽说现在是2015年但是JavaScript或者web都没有非阻塞式JSON API !所以对于这种情况,现在还没有原生的或除了盒式解决方法的其它办法。因为和一个线程通信是通过字符串,在一个进程中使用JSON.parse也是无意义的。
当我在浏览 Fetch API(window.fetch) 我注意到 Response 对象拥有一个异步.json方法。这是如何使用它的方法:
fetch('/foo.json')
.then(function(response) {
response.json().then(function(result) {
// result is parsed body of foo.json
});
});
我们可以使用(滥用?)这个API来将主线程中所有JSON-parsing业务移除出去。可以使用简单的方法来实现:
function asyncParse(string){
return (new Response(string)).json();
}
可以如预期的奏效:
asyncParse('{"foo": 1}').then(function (result) {
// result is {foo: 1}
});
将JSON.parse从主线程中移除使得实际的解析时间变得不那么重要啦,但是让我们看看它是如何与原生JSON.parse:
// jsonStr is 65,183 charctars console.time('sync: total time (blocking)');
JSON.parse(jsonStr);
console.timeEnd('sync: total time (blocking)');
console.time('async: blocking time');
console.time('async: total time');
asyncParse(jsonStr).then(function(result) {
console.timeEnd('async: total time');
});
console.timeEnd('async: blocking time');
sync: total time (blocking): 1.149ms
async: blocking time: 0.745ms
async: total time: 3.232ms
这个异步方法大约慢了2倍,但是正因为它是异步的,所以用它来阻塞UI的时候时间可以少于1ms。
我现在使用这个异步方法来实验,如果可行的话,我将会弄成一个包然后发布它。我希望JavaScript或者DOM可以提供原生的非阻塞式JSON API,所以我们没有必要来使用hacks。由于ES7(2016)async/await方法存在,使用异步方法将会变得更加容易,因此,我更应该使用异步JSON API。
扫码关注w3ctech微信公众号