w3ctech

非阻塞式异步JSON.parse方法使用Fetch API

非阻塞式异步JSON.parse方法使用Fetch API

提出问题

我正在研究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微信

扫码关注w3ctech微信公众号

共收到1条回复

  • fetch api已经可用了啊?

    回复此楼