Jan Hančič 公布了一个在一次请求里同时加载 CSS 和 JavaScript 的方案,platypus.js。
实现原理是利用 CSS 的 content
属性,把 JavaScript 转换成 base64 字符串放进去,再动态插入 DOM。
示例 CSS:
#platypus-0 {
display: none;
content: 'YWxlcnQoJ0hpLCBteSBmcmllbmQhIEZyb20gQ2hyaXMnKQo=';
}
示例 JS:
(function ( document ) {
var linkTags = document.querySelectorAll ( 'link[rel="stylesheet"]' );
for ( var i = 0; i < linkTags.length; i++ ) {
var dummyDiv = document.createElement ( 'div' );
dummyDiv.id = 'platypus-' + i;
document.body.appendChild ( dummyDiv );
var styles = document.defaultView.getComputedStyle ( dummyDiv, null );
var js = styles.getPropertyValue ( 'content' ); // w3c
//backgroundImage = someElement.currentStyle["background-image"]; //IE
if ( js === '' ) {
continue;
}
dummyDiv.parentNode.removeChild ( dummyDiv );
if ( js[0] === "'" || js[0] === '"' ) {
js = js.substr ( 1, js.length - 2 );
}
var scriptTag = document.createElement ( 'script' );
// window.atob - decode base64 string, unavailable on IE9-, MDN says IE10 supports it
scriptTag.innerHTML = atob ( js );
document.body.appendChild ( scriptTag );
};
} ( document ) );
按照 Jan 的说法,platypus.js 兼容非兼容视图的 IE9,大致上主流的桌面、移动浏览器都可以兼容。
这个方案很有意思,虽然 CSS 文件的大小增加了,但在越来越快的带宽和越来越好的 CDN 的影响下,DNS Lookup、Connecting 和 Wating 的消耗说不定比多出的部分少不了多少,特别是小文件。
我也想过利用 localStorage
来实现类似 manifest
的效果,简单的示例代码如下:
var load = (function() {
var insertToDOM, getSource
insertToDOM = function( content ) {
var script = document.createElement( 'script' )
script.textContent = content
document.body.appendChild( script )
}
getSource = function( file ) {
var source = localStorage.getItem( file )
if (typeof source !== 'string') {
// if no record, get source from server
$.ajax( {
url: file,
success: function( data ) {
localStorage.setItem( file, data )
insertToDOM( data )
}
} )
} else {
insertToDOM( source )
}
}
return function(files) {
files.forEach( function( file ) {
getSource( file )
})
};
})();
load( ['//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js',
'script.js'] )
特点:
- 可以支持很多文件,理论上能用 Data URI 加载的都可以;
localStorage
的访问速度远远快于 DNS Lookup 等消耗;localStorage
默认能支持最大 4MB 的储存,对于大部分站点完全足够;- 把脚本封装成
(fn)()
的形式并在底部插入特定的变量可判断版本、是否加载完成等,便于控制; - 可控性和易用性高于
manifest
,不需要配置服务器,需要清空时操作localStorage
即可,而localStorage
的存储持久性和manifest
基本一样。
只不过,这种做法和 AMD、CommonJS 等规范不太合拍——至少我还没想到好做法——小团队项目开发似乎挺不错,暂时只是草稿性质的想法。