pac脚本优化

最近发现lantern和shadowsocks client自生成pac都一定的性能问题,在url数目上升到一定程度的时候加载速度明显慢了很多.

于是我翻看了它们的实现

  • lantern
    • 把所有需要代理的domain组合成一个RegExp,然后在FindProxyForURL时对host做RegExp.exec的操作来判断是否需要代理
  • shadowsocks
    • 把domain做成一个{domain:1,…}的字典,然后在FindProxyForURL时对host做domains.hasOwnProperty判断是否在字典内,若不在,则去掉最前面的’.‘和之前的内容 继续做domains.hasOwnProperty判断

可以看出lantern的pac会严重影响网页的加载速度,shadowsocks的稍微好点,但在遇到不需要代理的网页时则会消耗更多无谓的判断 于是我自己实现一个pac优化FindProxyForURL匹配速度

我的思路是:

  • 把所有需要代理的url以 ‘.’ 分割成节点
  • 然后存入一个dict 格式如下
{
  "com": {
    "google": true,
    "blogspot": {
      "www": true  
    }
  }
}
  • 在FindProxyForURL中把host也split成list与这个dict match一下
var domains = [
    "google.com",
    "www.blogspot.com",
    ...
];
var domain_dict = {};
for(var i = 0; i < domains.length; i++){
    if(domains[i].endsWith(".")){
        domains[i] = domains[i].slice(0, -1)
    }
    var url_list = domains[i].split('.');

    var domain_node = domain_dict;
    for(var j = url_list.length; j > 0; j--){
        var node_name = url_list[j-1];
        if (!domain_node.hasOwnProperty(node_name)){
            if (j === 1){
                domain_node[node_name] = true;
                break;
            } else {
                domain_node[node_name] = {};
            }
        } else if(domain_node[node_name] === true) {
            break;
        }
        domain_node = domain_node[node_name];
    }
}

var proxy = "SOCKS5 127.0.0.1:1080; SOCKS 127.0.0.1:1080; DIRECT";

var direct = 'DIRECT;';

function FindProxyForURL(url, host) {
    if( host == "localhost" ||
        host == "127.0.0.1") {
        return direct;
    }
    var host_list = host.split('.')
    var domain_node = domain_dict
    for(var i = host_list.length; i > 0; i--){
        var node_name = host_list[i-1]
        if (domain_node.hasOwnProperty(node_name)){
            if(domain_node[node_name] === true){
                return proxy;
            } else {
                domain_node = domain_node[node_name]
            }

        }
        else {
            return direct;
        }
    }
    return direct;
}