BlogJava-emu in blogjavahttp://www.qpkxbc.shop/emu/zh-cnSun, 25 Aug 2019 00:09:04 GMTSun, 25 Aug 2019 00:09:04 GMT60整理了最近百年的藏歷數據,做了個公歷藏歷映射的小工具http://www.qpkxbc.shop/emu/archive/2019/01/30/433627.htmlemuemuWed, 30 Jan 2019 05:34:00 GMThttp://www.qpkxbc.shop/emu/archive/2019/01/30/433627.htmlhttp://www.qpkxbc.shop/emu/comments/433627.htmlhttp://www.qpkxbc.shop/emu/archive/2019/01/30/433627.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/433627.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/433627.html一個gihub項目里面,今年臨近藏歷新年,卻發現以往的很多藏歷網站都沒有更新明年的數據了,正好弄到了最近一百年的藏歷數據,花了點時間全部都更新了進去,順便申請了一個還不錯的域名 zangli.pro, 發布了一個新網站百年藏歷,方便大家隨時查詢或者在自己的產品中直接引用藏歷公歷的換算腳本。

emu 2019-01-30 13:34 發表評論
]]>
用webcrypto做AES原生加解密http://www.qpkxbc.shop/emu/archive/2017/06/12/432595.htmlemuemuMon, 12 Jun 2017 09:48:00 GMThttp://www.qpkxbc.shop/emu/archive/2017/06/12/432595.htmlhttp://www.qpkxbc.shop/emu/comments/432595.htmlhttp://www.qpkxbc.shop/emu/archive/2017/06/12/432595.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/432595.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/432595.html一個妹子聊到在前端做AES加密,妹子說有一些開源的庫,我想webcrypto提出來這么多年,應該主流瀏覽器很多也應該有原生的支持了吧?寫個加測試頁面試試看:

<!DOCTYPE html>
<html>
    <head>
        <META NAME="Author" CONTENT="emu">
        <META NAME="Keywords" CONTENT="webcrypto AES-CBC AES-GCM">
    </head>
    <body>
        <div id="out"></div>
        <script type="text/javascript">
            
function output(sign) {
                document.getElementById(
"out").innerHTML += sign + "<br>";
            }
            
function bufferToHex(b){
                
var dataview = new DataView(b);
                result 
= "";
                
for (var i = 0; i < b.byteLength; i += 4) {
                    tmp 
= dataview.getUint32(i).toString(16);
                    result 
+= (tmp.length == 8 ? "" : "0"+ tmp;
                }
                
return result;
            }

            
function bufferToString(b){
                
//new TextDecoder().decode(b)
                var hex=bufferToHex(b);
                
var result=unescape(hex.replace(/(..)/g,"%$1"));
                
return result;
            }
            
function stringToBuffer(s){
                
//new TextEncoder().encode(s);
                 var a = s.split("");
                 
for (var i = 0; i < a.length; i++) {
                        a[i] 
= a[i].charCodeAt(0)
                 };
                 
var result = new Uint8Array(a);
                 
return result;
            }


        
var textToBeEncrypted = 'Hello World!';
        
var bufferToBeEncrypted=stringToBuffer(textToBeEncrypted);
        
var bufferToBeDecrypted;
        
var pwd="let me try this password"
        
var password = stringToBuffer(pwd);
        
var sAlg="AES-CBC";//AES-GCM部分瀏覽器不支持
        var c = window.crypto || window.msCrypto;
        
var subtle = c.subtle || c.webkitSubtle;
        
var iv = c.getRandomValues(new Uint8Array(16));
        
var alg = { name: sAlg, iv: iv };
        
var op=c.subtle.digest('SHA-256', password)
        
var encryptKey,decryptKey,hash;
        
if(("then" in op)){
            op.then(
function(buffer){
                hash
=buffer;
                c.subtle.importKey('raw', hash, alg, 
false, ['encrypt']).then(function(buffer){
                    encryptKey
=buffer;
                    c.subtle.importKey('raw', hash, alg, 
false, ['decrypt']).then(function(buffer){
                    decryptKey
=buffer;
                    doEncrypt(alg,encryptKey);
                    })
                })
            });
        }
else{
            op.oncomplete
=function(e){
                
var hash=e.target.result;
                
var op=c.subtle.importKey('raw', hash, alg, false, ['encrypt']);
                op.oncomplete
=function(e){
                    encryptKey
=e.target.result;
                    op
=c.subtle.importKey('raw', hash, alg, false, ['decrypt']);
                    op.oncomplete
=function(e){
                        decryptKey
=e.target.result;
                        encryptWithCryptoOperation(alg,encryptKey);
                    }
                }
            }
        }
        
function doEncrypt(alg,encryptKey){
            
var op = c.subtle.encrypt(alg, encryptKey, bufferToBeEncrypted);
            op.then(
function(buffer){
                    bufferToBeDecrypted
=buffer;
                    output(
"pwd: <b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>encrypt("+textToBeEncrypted + ")="+ bufferToHex(buffer));
                    doDecrypt(alg,decryptKey);
                })
        }

        
function doDecrypt(alg,decryptKey){
            
var op = c.subtle.decrypt(alg, decryptKey, bufferToBeDecrypted);
            op.then(
function(buffer){
                output(
"pwd:<b><i>"+pwd+"</i></b>  alg:<b>"+sAlg+"</b> <br>decrypt("+bufferToHex(bufferToBeDecrypted) + ")="+ bufferToString(buffer));
            })
        }

        
function encryptWithCryptoOperation(alg,encryptKey){
            
var op = c.subtle.encrypt(alg, encryptKey);
            op.onerror
=function(e){output(sAlg+"  unsupported")}
            op.process(bufferToBeEncrypted);
            op.oncomplete
=function(e){
                bufferToBeDecrypted
=e.target.result
                    output(
"pwd: <b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>encrypt("+textToBeEncrypted + ")="+ bufferToHex(bufferToBeDecrypted));
                
//decryptWithCryptoOperation(alg,decryptKey)
                setTimeout(decryptWithCryptoOperation,0,alg,decryptKey)
            }
            op.finish();
        }        
        
function decryptWithCryptoOperation  (alg,decryptKey){
            
var op = c.subtle.decrypt(alg, decryptKey);
            op.onerror
=function(e){(sAlg+"  unsupported")}
            op.process(bufferToBeDecrypted);
            op.oncomplete
=function(e){
                
if(!e.target.result){
                    output(
"IE is crazy!<br>");
                    encryptWithCryptoOperation(alg,encryptKey)
                }
else
                    output(
"pwd:<b><i>"+pwd+"</i></b>  alg:<b>"+sAlg+"</b> <br>decrypt("+bufferToHex(bufferToBeDecrypted) + ")="+ bufferToString(e.target.result));
            }
            op.finish();
        }
        
</script>
    </body>
</html>

測試下來感覺各個瀏覽器支持程度還是參差不齊,IE11和Edge都是不同的實現方式,IE11甚至還會隨機出現oncomplete的時候result數據都還沒有ready的情況,甚至于有的時候完全相同的入參(包括隨機數也相同)加密出來的結果居然會不同,也就是說有的時候加密算法自己會加密錯,出來的結果根本就無法被正確解密,實在是個半成品:


(第一次加密錯了,第二次加密對了解密錯了,第三次終于加解密都對了)


(第一次加密錯了,第二次對了)


emu 2017-06-12 17:48 發表評論
]]>
用優圖繼續優化論壇http://www.qpkxbc.shop/emu/archive/2016/02/27/429464.htmlemuemuSat, 27 Feb 2016 12:21:00 GMThttp://www.qpkxbc.shop/emu/archive/2016/02/27/429464.htmlhttp://www.qpkxbc.shop/emu/comments/429464.htmlhttp://www.qpkxbc.shop/emu/archive/2016/02/27/429464.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/429464.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/429464.html

加好后,流量唰唰唰的就掉下來了:







每天流量從20G~30G下降到1G以下,相應的優圖流量也上到接近2G。



哎呀,前面買了個大流量包這下怎么用的完啊?




emu 2016-02-27 20:21 發表評論
]]>
用騰訊云優化一個公益論壇http://www.qpkxbc.shop/emu/archive/2016/02/19/429374.htmlemuemuFri, 19 Feb 2016 09:56:00 GMThttp://www.qpkxbc.shop/emu/archive/2016/02/19/429374.htmlhttp://www.qpkxbc.shop/emu/comments/429374.htmlhttp://www.qpkxbc.shop/emu/archive/2016/02/19/429374.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/429374.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/429374.html〇、背景

       幾年前由于發起尋親項目的關系,和B網站開展了合作。B網站是國內最大的尋親網站,幾年來通過該網站和家人團聚的案例已經達到1397例。B論壇是網站中最活躍的板塊。當時論壇遇到一些不穩定的情況,因為B論壇是用Discuz!搭建的,而Discuz!當時剛好被騰訊收購,要獲得專業支持相對容易,我們開始把B論壇遷移到騰訊云上面,由Discuz!的志愿者協助維護直到去年底離職,把論壇的管理權限交給我。

一、論壇出問題了

      我不對于php和linux都不熟,交接后看到論壇工作還算正常,也很長一段時間沒有去關注,直到前幾天,網站管理員突然發來了這個:




這是什么鬼?臣妾不懂啊……只好硬著頭皮登上服務器去看看。



還好,大概可以猜到出什么事了:數據盤不夠用了。那應該很好解決吧?擴數據盤?

二、COS

用騰訊云服務器而不是自己買服務器的一個好處就是,很多資源可以按需用,按需擴,包括硬盤。不過有個限制就是,買服務器的時候系統盤和數據盤都必須要買“云硬盤”而不能用本地盤。買云硬盤還有個附加的好處是可以申請開通硬盤快照功能,遷移復制服務器唰唰的。

但是云硬盤的性能跟本地硬盤是有差距的,處于性能考慮,志愿者選擇了性能更好的本地硬盤,這樣就導致硬盤滿了以后沒有辦法擴了。幾年來,尋親的網友們每天上傳大量的高清圖片線索,終于在世紀寒流這幾天把硬盤擠爆了。



不過擴硬盤本來也不是最佳選擇,比擴硬盤更好的選擇是:不用硬盤!

騰訊云為這種UGC文件提供的解決方案是
COS(Cloud Object Service ,當前版本是COS3.0。COS 大概的意思就是,你有一大堆文件(比如網站用戶上傳的照片),只知道量很大,不知道有多少,不但需要找個地方存著,還隨時有可能需要在某個網頁上引用它。那么平臺提供一個服務器讓你把文件放上去,并提供web訪問和API上傳和管理接口,你就不用把文件傳到自己服務器了。

個人認為使用COS的好處是:
1 能夠提供幾乎無限量的文件存儲空間,按存儲量和訪問量收費
2 很大的免費額度:50G的免費空間,每計費周期內10G的回源流量,每計費周期內100萬次的免費訪問次數(實際上COS通常在CDN后面提供服務,因此實際上每個計費周期可以提供10G和100萬次回源服務,配合恰當的CDN緩存策略,已經可以滿足很大的訪問量)。
因此用cos不但從此不用糾結容量爆倉的問題,也不用為沒有使用到的容量預先買單花冤枉錢,而且還不用自己的服務器的硬盤和網卡來扛這些流量,服務器的帶寬和硬盤I/O壓力也立刻就下來了。

COS的使用也很簡單:
1 建個倉庫(bucket),以后附件就往這個倉庫里面傳了。


2 修改上傳附件頁面,使用騰訊云提供的API把文件上傳到COS……開玩笑了,作為懶人,當然是提工單申請開通COS的FTP權限啦



大概兩個鐘頭后收到消息說ftp開通了。

3 用論壇創始人身份登錄discuz,打開遠程附件


遠程訪問url可以域名解析到COS源上,不過這樣附件都要走IDC流量,不但貴,也沒有實現靜態文件就近訪問的目標,因此實際使用的時候最好在COS服務的上面加一層CDN:
 



現在用戶新上傳的附件都自動到cos里面了。然后我們來對付舊的附件吧。這時我們要用到回源功能了。先準備好一個回源專用的域名,修改httpd.conf(apache)或者conf.d(nginx)添加一個新的server,documentroot(或者root)指向服務器上discuz的附件目錄 data/attachment 并修改域名解析,瀏覽器里面訪問一下確認回源域名可以訪問到附件。然后修改cos的回源配置:




這樣如果有人訪問cos的時候cos上沒有相應的文件,服務器就會到老的服務器上獲取文件并緩存下來。通過瀏覽器訪問附件確認回源成功后,登錄數據庫 
update cdb_attachments set remote = '1' 把所有的附件都更新為遠程的。這樣數據就會隨著用戶的訪問慢慢遷移到cos上了,這個過程平滑無感知,不過就是不知道遷移到什么時候成功。

可是我想釋放硬盤空間出來啊怎么辦?先裝上ftp神器 lftp再說。不得不說,在linux下,lftp實在是個神器。打開lftp,open登上COS的ftp服務器,mirror -RL ..... 老附件通通遷移上COS咯。

偷懶用ftp而不是修改上傳頁面代碼的一個代價是,有的時候ftp失敗,會有一些附件仍然被扔在CVM硬盤上。可以定期
update cdb_attachments set remote = '1' 把附件都改成遠程的,讓cos回源到CVM上。不過就算這樣,冷門的附件仍然可能長時間沒有辦法同步到cos上。crontab一個lftp任務定期把附件同步上COS可以解決問題。不過如果懂一點點開發的話,寫一點點腳本用inotify自動同步一下顯得會看起來好點兒:







三、 CDN優化:動靜分離

      內容分發網絡(Content Delivery Network)大概的意思就是,我大騰訊在全國成百上千個機房里面屯有無數的服務器,如果某個邊遠地區的用戶要訪問你放在上海的一份數據,山長水遠的跑到上海機房來拉數據肯定快不了,如果我把這份數據先放在這個邊遠地區里,離用戶最近的一個機房呢?那速度就不一樣了。而且這個邊遠地區的機房流量還比我大上海三通機房的流量便宜了一大截。不過有個前提是服務器要提前知道用戶將要訪問的數據,并提前拉取這份數據緩存在當地,因此一般只用來服務靜態的圖片、樣式表、腳本、超文本、flash這些資源。



      B論壇其實去年就用上了CDN,不過用的是一個比較冷門的用法:動態加速。這個用法就是說,先假設我網站的所有請求都是靜態的,這樣用戶所有的請求都訪問在當地的服務器(邊緣服務器),然后邊緣服務器檢查一下這個請求的資源我有沒有緩存啊,沒有的話邊緣服務器再受累跑去你的服務器上拉這個數據,把數據返回給你,并且嘗試緩存這個數據以備下次使用。然后對于不允許緩存的動態請求,只要聲明一個策略,比如“php文件緩存時間0秒”這樣,讓邊緣服務器直接訪問源CVM服務器就好了。

    這樣做的好處是配置簡單,不需要關心動靜分離,并且不但靜態的文件都可以被邊緣服務器緩存,動態的請求也可以獲得cdn網絡的傳輸加速 。壞處就是“流量double”。也就是說,你不但要給cvm購買外網帶寬,cvm的動態數據送到邊緣服務器以后,你還要再購買一次從邊緣服務器到用戶那里的cdn帶寬(或者流量)。

    另外一個附加的“缺點”是,CDN網絡總是盡可能快的從CVM服務器拉取全部數據,再按照訪客用戶網絡的速度再把數據吐出去。這其實是最佳策略,因為CVM的帶寬已經買單了,不跑慢也是浪費,但是帶來的問題就是CVM監控上看起來,再多的帶寬都會被跑滿,好像帶寬永遠都不夠用。因此前任的管理員購買了非常多的帶寬來試圖滿足永遠喂不飽的CDN網絡,帶寬成了B論壇最沉重的成本。
    

 
(15M的帶寬,經常性的被CDN跑滿) 


    貿然的減少帶寬也是不合適的,最好的做法還是做盡量徹底的動靜分離,靜態的部分還是用cos托管源和FTP托管源來喂飽CDN網絡,讓用戶盡可能體驗好;動態的部分直接訪問CVM,根據用戶日常實際產生的帶寬情況再加上足夠充分的冗余來采購就可以。

    傳統的動靜分離手段是最好的:直接修改html、css和js,通過靜態專用域名訪問靜態資源。但是這樣做需要很多的開發工作量,作為懶人,我直接用上了大殺器:rewrite!




    懶得給每個域名打馬賽克了,也不是什么機密。這幾條規則是這樣:
1 對于普遍圖片超大的png圖片,自動轉向到優圖系統進行jpg壓縮。因為監控發現少數png圖片占了很大的流量比重。
2 對于用戶上傳到附件,自動轉向到attachment子目錄(COS源),這樣CVM就不需要承擔附件文件的存儲了(零星缺失的文件cos回源啟用了回源專用的域名)
3 對于系統的靜態文件,自動轉向到static子目錄(FTP源),不統一使用cos源的原因是,CDN回源到ftp源是免費的,但是ftp源只有6G的存儲空間。回源到cos空間幾乎是無限的,但是是有可能收費的。
這樣就把CVM上出了favicon.ico之外的幾乎所有靜態文件都分離出去了。要注意的是如果盜鏈嚴重的話,原本nginx上的防盜鏈規則也要相應的設置到cdn上去。




動靜分離后cdn的整體命中率從瓶頸50%以下一下提升到75%以上,對于cvm的壓力大大減小了。看一下分域名的命中率數據




在不對論壇程序做細致的優化的情況下,只是通過策略調整達到這樣的命中率,還算比較理想了。

不過這樣做了以后,CDN的流量費用并沒有下降啊。因為B論壇的CDN采用了峰值帶寬計費模式,因此觀察了一下cdn監控的帶寬數據,發現了一個很有意思的問題:



CDN的峰值帶寬按天波動非常大。細看到具體的帶寬比較大的一天更明顯:



這天是央視《感動中國2016》B論壇的兩個發起人入選帶來的一個訪問波峰。

像這樣的帶寬曲線模式,按照帶寬購買CDN是非常浪費的。果斷切換到流量包計費模式,CDN費用從每月>¥500(每年大約¥6000~¥8000)下降到每年<6T(每年大約2000以內)

動靜分離后CVM的實際動態帶寬需求有多少呢?后面上了負載均衡之后沒有地方可以截屏幾臺服務器完整的帶寬總和曲線了,總體是2M帶寬平常跑不滿,但是偶發集中的訪問會超,所以兩臺CVM做負載均衡,各開了2M的帶寬,保證平常有超過一倍的帶寬冗余。


四:memcache和云數據庫

B論壇遷移到騰訊云的時候就使用了云數據庫,數據量雖然不大,但是數據庫訪問量不小,購買的是能支撐2400QPS的50G/2000MB型號。


 (7天后到期,不需要續了) 

但是查看了一下discuz的優化選項,發現內存緩存優化項都沒有打開。在CVM里裝上一個memcached測試了一下,數據庫請求可以有效的降低到100QPS以下。這樣高配云數據庫就太浪費了,換個10G/360MB/120QPS的就足夠了。不過性能冗余夠不夠?discuz支持master/slave的,先提個工單申請一個免費的slave。



配置slave后觀察了幾天,即使在峰值查詢接近700QPS的情況下數據庫也沒有出現訪問瓶頸,騰訊云數據庫的性能還是相當厚道的,這個性能冗余是足夠的。




(某海量網站配置錯誤導致出現大量404頁面,順帶給論壇帶來了很大壓力)

這樣數據庫費用從¥2240/年陡降到¥210/年了。已經省了這么多錢,再買個C型的memcached好了,每天2元,每年大概700元。
CVM本機運行一個memcached雖然性能不錯,但是始終要和其他本機服務競爭各種資源,而且考慮到后面要做負載均衡,也希望把登錄態(session)丟到云里面去。


(memcache很輕松的扛住了情人節的感動中國帶來的訪問量)


修改了一下discuz的配置文件指向memcached,再修改php.ini把session也指向了memcached,這下CVM就沒有“狀態”了,可以很容易的替換,或者集成多個做負載均衡。

五:CVM和負載均衡



B論壇在騰訊云上一共兩臺CVM,對外提供服務的是一臺配置有點豪華的服務器:



這臺每年費用是 ¥16450,當然主要的錢都花在買帶寬去喂CDN了



另一臺不對外服務,只是有一個大的硬盤做數據備份。


一年¥1550。

經過上面一系列優化以后,原本買的CVM性能就太過冗余了,文件都丟到COS上去了,大硬盤備份也沒有必要了。已經遷移到cos的文件剔除后,整個系統只剩下了4G,全部回遷到系統盤上面,數據盤也不需要了:



因為數據庫在云上,附件文件也在cos上,本地沒有什么動態的數據,這樣系統備份也簡單的多了,定期對系統盤做一個“系統鏡像”就成,除了有一個問題:做系統鏡像要關機。

墨菲定律告訴我們,永遠要防著機器宕機!前面該清理的清理干凈了,是時候做雙機熱備了。先把備份機的論壇服務也啟動起來,session也指向memcached,然后添加一個負載均衡:


訪問低谷的時候把主服務器關掉,做鏡像,備份機自動扛住了全部訪問量。

有了鏡像以后換機型就方便了。新購一臺服務器




因為充分使用了云數據庫、memcache、cdn、cos等paas服務,又做了動靜分離,cpu現在已經清閑的很,1核的性能是足夠的。內存使用率也很低,內存其實1G也足夠,不過cpu不夠了還可以負載均衡,內存不夠了就只有干瞪眼,所以多加1G冗余。

購買的時候就可以直接指定安裝鏡像,支付每年¥1250的費用,10分鐘后,有了一臺全新的服務器,配置host驗證成功,加入到負載均衡后端列表里面

把權重分幾次從原來的高配服務器分配到新服務器上,運行指標都還好,就是負載有點兒高,訪問速度可能不是最優,也許是mysql或者memcache要通過網絡訪問導致的?



反正要做雙機熱備的,再買一臺一樣的服務器,加入負載均衡后臺分攤一半的訪問量,觀察了一下cpu利用率和負載都下來了,雖然偶爾有一些瞬間的毛刺,反問上已經感覺不到差別。



這樣就有了兩臺一模一樣的服務器,平常分攤訪問壓力,一臺宕機的時候負載均衡會自動發現并把訪問全部導向到正常工作的服務器。未來如果有更大的訪問壓力隨時可以新購機器,安裝上鏡像后加入負載均衡后端。

正好原來購買的服務器和數據庫這陣子都要過期了,就都不用續費了。

六、對公益捐贈負責 

看看優化后比原來節省了多少:

CVM: 原來16450+1550=18000 , 優化后1250*2=2500



CDN+COS:原來:¥6000~¥8000,優化后約 ¥2000(COS回源流量暫時還沒收費,附件遷到cos后也不足50G還不需要存儲費用,不過未來有可能產生少量費用。)

mysql+memcache :原來 ¥2240,優化后210+700=910

總體相比原來優化大約 ¥22000 /年。

  雖然騰訊云一直對于公益組織免費扶持云資源,但是我覺得云資源和公益捐贈善款一樣,也要用負責的態度摳門的用好,才是對支持企業負責任的態度。

最后,感謝騰訊云對公益事業的慷慨支持。打完收工。








emu 2016-02-19 17:56 發表評論
]]>
jq的getScript函數不支持chaset?override掉!http://www.qpkxbc.shop/emu/archive/2014/11/19/420314.htmlemuemuWed, 19 Nov 2014 11:40:00 GMThttp://www.qpkxbc.shop/emu/archive/2014/11/19/420314.htmlhttp://www.qpkxbc.shop/emu/comments/420314.htmlhttp://www.qpkxbc.shop/emu/archive/2014/11/19/420314.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/420314.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/420314.html
其實我從來不用jq或者其他框架的,這兩天偶然在一個小項目里面發現jq的一個小bug:getScript函數沒有透傳charset信息,如果試圖在頁面上加載一個跨編碼的腳本的時候會導致編碼錯誤。寫了一個補丁函數覆蓋掉原來的:

$.getScript=function(url, callback , charset){
    $.ajax({
        url: url,
        dataType: "script",
        success:callback,
        scriptCharset:charset
    })
}    

這幾年代碼寫得很少,輕噴。這里是demo代碼 ,同時也到jq的github上提交了一個issue

<!DOCTYPE html>
<HTML>
<HEAD>
<meta charset="utf-8" />
<script src="http://cdn.jsdelivr.net/jquery/1.11.1/jquery.js"></script>

<SCRIPT LANGUAGE="JavaScript">
<!--
function log(s){
    $(
"body")[0].innerHTML+="<p>"+s.replace(/\n/g,"<br>").replace(/\t/g,"&nbsp&nbsp&nbsp&nbsp")+"</p>";
}
function testBIG5(result){
    log(
"BIG5 decode "+(result?"correctly":"<font color=red>incorrectly</font>"))
}
function testGB(result){
    log(
"gb2312 decode "+(result?"correctly":"<font color=red>incorrectly</font>"))
}
function testUTF8(result){
    log(
"utf-8 decode "+(result?"correctly":"<font color=red>incorrectly</font>"));
}
function testJP(result){
    log(
"iso-2022-jp decode "+(result?"correctly":"<font color=red>incorrectly</font>"));
}
function testKR(result){
    log(
"euc-kr decode "+(result?"correctly":"<font color=red>incorrectly</font>"));
}
$(document).ready(
function(){

    $.when(
        log(
"<i>old version of getScript:</i>"),
        log($.getScript.toString()),
        $.getScript(
"http://stonelf.sinaapp.com/testGB.js"),
        $.getScript(
"http://stonelf.sinaapp.com/testUTF8.js"),
        $.getScript(
"http://stonelf.sinaapp.com/testBIG5.js"),
        $.getScript(
"http://stonelf.sinaapp.com/testJP.js"),
        $.getScript(
"http://stonelf.sinaapp.com/testKR.js")
    ).then(
function(){

        $.getScript
=function(url, callback , charset){
            $.ajax({
                url: url,
                dataType: 
"script",
                success:callback,
                scriptCharset:charset
            })
        }    

        log(
"<hr><i>new versioni of getScript:</i>");
        log($.getScript.toString()),
        $.getScript(
"http://stonelf.sinaapp.com/testGB.js",undefined,"gb2312");
        $.getScript(
"http://stonelf.sinaapp.com/testUTF8.js",undefined,"utf-8");
        $.getScript(
"http://stonelf.sinaapp.com/testBIG5.js",undefined,"big5");
        $.getScript(
"http://stonelf.sinaapp.com/testJP.js",undefined,"iso-2022-jp");
        $.getScript(
"http://stonelf.sinaapp.com/testKR.js",undefined,"euc-kr");

    })
})
//-->
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>


emu 2014-11-19 19:40 發表評論
]]>
大家好像都比較少關心webcrypto,試試寫個簡單的sha1/sha256/sha384/sha512實現看看http://www.qpkxbc.shop/emu/archive/2014/09/27/webcrypto.htmlemuemuSat, 27 Sep 2014 13:40:00 GMThttp://www.qpkxbc.shop/emu/archive/2014/09/27/webcrypto.htmlhttp://www.qpkxbc.shop/emu/comments/418336.htmlhttp://www.qpkxbc.shop/emu/archive/2014/09/27/webcrypto.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/418336.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/418336.html<!DOCTYPE html>
<html>
    <head>
        <META NAME="Author" CONTENT="emu">
        <META NAME="Keywords" CONTENT="webcrypto sha1 sha256 sha384 sha512">
    </head>
    <body>
        <div id=sha></div>
        <script type="text/javascript">
            
function output(sign) {
                document.getElementById(
"sha").innerHTML += sign + "<br>";
            }
            
function bufferToHex(b){
                
var dataview = new DataView(b);
                result 
= "";
                
for (var i = 0; i < b.byteLength; i += 4) {
                    tmp 
= dataview.getUint32(i).toString(16);
                    result 
+= (tmp.length == 8 ? "" : "0"+ tmp;
                }
                
return result;
            }
            
function digest(s, callback, algorithm, errCallback) {
                
try {
                    
if (!errCallback) {
                        errCallback 
= callback;
                    }
                    
var c = window.crypto || window.msCrypto;
                    
var subtle = c.subtle || c.webkitSubtle;
                    
if (!algorithm) algorithm = "SHA-512";
                    
var a = s.split("");
                    
for (var i = 0; i < a.length; i++) {
                        a[i] 
= a[i].charCodeAt(0)
                    };
                    
var data = new Uint8Array(a);
                    
var op = subtle.digest({
                        name: algorithm
                    }, data);
        
                    
if("then" in op){
                        op.then(
                            
function(buffer) {
                                callback(bufferToHex(buffer));
                            }, 
function(e) {
                                errCallback(e);
                            })
                    }
else{
                        op.oncomplete
=function(s){                    
                            callback(bufferToHex(s.target.result));
                        }
                    }
                } 
catch (e) {
                    errCallback(e);
                }
            }
            digest(
"test"new Function("output('sha-1(<i>test</i>) : '+arguments[0])"), "SHA-1");
            digest(
"test"new Function("output('sha-256(<i>test</i>) : '+arguments[0])"), "SHA-256");
            digest(
"hello"new Function("output('sha-384(<i>hello</i>) : '+arguments[0])"), "SHA-384");
            digest(
"world"new Function("output('sha-512(<i>world</i>) : '+arguments[0])"), "SHA-512");
        
</script>

    </body>
</html>
使用了瀏覽器原生接口,對舊瀏覽器沒有什么兼容性可言了,尤其是IE,一時半會兒還用不上。

emu 2014-09-27 21:40 發表評論
]]>
下周一國際盲人節,查了一下網上的盲文資料寫了一個把中文轉換成盲文的腳本玩玩。http://www.qpkxbc.shop/emu/archive/2012/10/12/389481.htmlemuemuFri, 12 Oct 2012 09:41:00 GMThttp://www.qpkxbc.shop/emu/archive/2012/10/12/389481.htmlhttp://www.qpkxbc.shop/emu/comments/389481.htmlhttp://www.qpkxbc.shop/emu/archive/2012/10/12/389481.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/389481.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/389481.html<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "...  閱讀全文

emu 2012-10-12 17:41 發表評論
]]>
偶然發現7年前受到的offer。7年,一晃而過http://www.qpkxbc.shop/emu/archive/2012/08/27/386379.htmlemuemuMon, 27 Aug 2012 11:21:00 GMThttp://www.qpkxbc.shop/emu/archive/2012/08/27/386379.htmlhttp://www.qpkxbc.shop/emu/comments/386379.htmlhttp://www.qpkxbc.shop/emu/archive/2012/08/27/386379.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/386379.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/386379.html黃XX 先生 :
     我非常高興地通知您,經過我公司的面試和討論,我們一致認為您是我公司 互聯網事業部 開發工程師 的合適人選。
根據公司的薪資福利政策,我們將給您提供以下薪酬福利待遇:
   (一) 月薪(稅前):
         試用期xxxx元, 轉正后xxxx元
         附加信息:
         試用期3個月
         年終發放雙薪。
         特別說明: 按照公司規定,月薪中的15~20%(視崗位性質而定)為浮動工資,將結合每月績效成績,在每季度末統一發放。
 (二)季度獎金:
         每季度結束,將根據當季度個人的業績發放季度獎金。
   (三)年終獎金:
         每年度結束,將根據公司經營業績和個人考核成績,發放年終獎金。
  (四)員工福利:
         公司為員工辦理社會保險,并為員工提供各項優厚福利,包括:帶薪假期、節日費、員工婚育禮金等,并資助員工的各項活動。
       騰訊公司和諧的企業文化氛圍一定會讓您感受到集體的溫暖。
       (以上員工福利待遇信息為保密資料,請勿向公司內外的其他人員透露。同時公司禁止兼職,并嚴格要求IPR保護及競業限制等)
        如接受我公司的OFFER,請回復郵件說明;如對OFFER有任何疑問,也請盡快回復郵件說明,或致電0755-86013388轉7031人力資源部luis(劉德志)聯系。
        此OFFER兩周內有效。
        備注:此錄用OFFER已確認了您的專業資格,如果您確認此錄用OFFER,我司相關人員將通知您入職資格(體檢、驗證等)的審核事宜
。若入職資格的審核(體檢、驗證等)不符要求,此offer將自動取消。故提醒您在前任單位離職前,先與我司做入職資格(體檢、驗證等)的確認。
 
 
 
        此致!
 
                                                                      騰訊科技(深圳)有限公司
                                                                            2005-8-19
@import url(http://www.qpkxbc.shop/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

emu 2012-08-27 19:21 發表評論
]]>
學習了一下條件注釋http://www.qpkxbc.shop/emu/archive/2012/01/11/368358.htmlemuemuWed, 11 Jan 2012 11:51:00 GMThttp://www.qpkxbc.shop/emu/archive/2012/01/11/368358.htmlhttp://www.qpkxbc.shop/emu/comments/368358.htmlhttp://www.qpkxbc.shop/emu/archive/2012/01/11/368358.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/368358.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/368358.html
<!--[if IE]> IE才看得到,非IE看不到 <![endif]-->
<!--[if !(IE)]><!--> IE看不到,非IE才看得到 <!--<![endif]-->


emu 2012-01-11 19:51 發表評論
]]>
多年來頭一回用到tdchttp://www.qpkxbc.shop/emu/archive/2011/12/30/367568.htmlemuemuFri, 30 Dec 2011 04:23:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/12/30/367568.htmlhttp://www.qpkxbc.shop/emu/comments/367568.htmlhttp://www.qpkxbc.shop/emu/archive/2011/12/30/367568.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/367568.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/367568.html


拷貝出來以后居然是一個龐大的xml文本,咋看呢。突然想起來有個IE特性專門用來干這個的,可能快有10年沒用了,查查手冊,很容易就做出了個頁面

<HTML>
<HEAD>
<BODY>
<xml id="xxx"><default><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app905_905_50.png" size_bytes="1535" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app905_905_16.png" size_bytes="216" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app608_608_50.png" size_bytes="9619" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app502_502_50.png" size_bytes="4557" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app501_501_50.png" size_bytes="2639" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app389_389_50.png" size_bytes="2018" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app389_389_16.png" size_bytes="1250" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app381_381_50.png" size_bytes="9727" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app381_381_16.png" size_bytes="1216" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app375_375_50.png" size_bytes="3831" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app372_372_50.png" size_bytes="1748" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app372_372_16.png" size_bytes="582" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app371_371_50.png" size_bytes="3820" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app371_371_16.png" size_bytes="533" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app370_370_50.png" size_bytes="9097" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app367_367_50.png" size_bytes="6109" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app365_365_50.png" size_bytes="5383" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app364_364_50.png" size_bytes="1701" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app363_363_50.png" size_bytes="2357" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app361_361_50.png" size_bytes="1397" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app359_359_50.png" size_bytes="2723" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app356_356_50.png" size_bytes="3839" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app355_355_50.png" size_bytes="3495" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app354_354_50.png" size_bytes="5209" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app353_353_50.png" size_bytes="3696" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app353_353_16.png" size_bytes="583" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app350_350_50.png" size_bytes="4318" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app346_346_50.png" size_bytes="2256" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app345_345_50.png" size_bytes="3462" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app24341_24341_50.png" size_bytes="3096" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app24341_24341_16.png" size_bytes="793" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app201_201_50.png" size_bytes="3426" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app201_201_16.png" size_bytes="452" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app11165_11165_50.png" size_bytes="3747" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:34 GMT (expires)"/><networkactivity url="http://ctc.qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app11165_11165_16.png" size_bytes="1939" total_s="0.00" mime="image/png" cache_expiration="30 Dec 2011 04:04:28 GMT (expires)"/></default></xml>

<TABLE DATASRC= "#xxx" cellspacing=1 bgcolor=black style="font-size:13px">
<THEAD bgcolor=white> 
<TR> 
<th>cache_expiration</th> 
<th>url</th> 
<th>size_bytes</th> 
<th>img</th> 
</TR> 
</THEAD> 
<TBODY bgcolor=white> 
<TR> 
<TD><SPAN DATAFLD="cache_expiration"></SPAN></TD> 
<TD><SPAN DATAFLD="url" style="width:600px;word-break:break-all"></SPAN></TD> 
<TD><SPAN DATAFLD="size_bytes"></SPAN></TD> 
<TD><DATAFLD="url" target="_blank"><img DATAFLD="url" /></a></TD> 
</TR> 
</TBODY> 
</TABLE> 
</BODY>
</HTML>
出來的界面還是可以一看的







emu 2011-12-30 12:23 發表評論
]]>
簡單的文本描邊函數,寫著玩兒。http://www.qpkxbc.shop/emu/archive/2011/09/15/358694.htmlemuemuThu, 15 Sep 2011 06:04:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/09/15/358694.htmlhttp://www.qpkxbc.shop/emu/comments/358694.htmlhttp://www.qpkxbc.shop/emu/archive/2011/09/15/358694.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/358694.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/358694.html<html>
<body>
<div style="height:100%; width:50%; background-color:black; position:absolute; left:0px; top:0px"></div>
<div id="test" style="position:absolute;left:40%;top:120px; color:white;z-index:100">主頁 <B>日志</B> <I>相冊</I> <U>留言板</U> <FONT SIZE="10">心情</FONT> 音樂<pre>丹東韶關限價令引質疑:限價為躲限購
[部分城市出臺樓市限價令被指變相抵制限購令] [19城市成交量下滑]
[四成房企業績增長] [濟青樓市大搞優惠] [杭州半數樓盤成交不足2成]
上海一員工班車側翻 已致11人死13人傷
[6名危重患者中4人病情已趨穩定] [俞正聲韓正指示全力搶救傷員]
藥劑師曝購買魚精蛋白被強制搭售另一藥
上海地鐵8號線早高峰出故障 乘客稱3站開35分鐘13:18
湖北省委巡視辦否認接受貧困縣“天價接待”07:12
西安一退休干部雇兇殺46歲情婦 4名嫌犯先后落網07:24
富人官員與無房者爭搶 浙江上演經適房烏龍鬧劇10:23
湖南郴州原副市長雷淵利:被情人弄得暈頭轉向10:35
市民買到發霉漢堡包 肯德基被判10倍賠償09:02
李陽談家暴承認恨妻子:當時把她頭撞地上好多下
</pre></div>

<script type="text/javascript">
<!--
function backgound(e,color){
    
if(e==document.body) return;
    
var t=new Date();
    
for(var x=-1;x<2;x++){
        
for(var y=-1;y<2;y++){
            
if(x!=0||y!=0){
                
var e0=e.cloneNode(true);
                e0.style.zIndex
=99
                e0.style.color
=color;
                e0.style.marginLeft
=x+"px";
                e0.style.marginTop
=y+"px";
                e.parentNode.insertBefore(e0,
null)
            }
        }
    }
}
backgound(document.getElementById(
"test"),"gray");
//-->
</script>

 
</body>
</html>


emu 2011-09-15 14:04 發表評論
]]>
IE下對文件(圖片)進行base64轉換http://www.qpkxbc.shop/emu/archive/2011/08/28/357431.htmlemuemuSun, 28 Aug 2011 04:11:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/08/28/357431.htmlhttp://www.qpkxbc.shop/emu/comments/357431.htmlhttp://www.qpkxbc.shop/emu/archive/2011/08/28/357431.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/357431.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/357431.html在編寫某個hta的用戶環境分析工具的時候,經常發現用戶被一些莫名其妙的代理服務器所劫持以后,一個正常的文本請求卻下載到了一個圖片。這種log看多了以后sidney就開始投訴了,想搜集到用戶那里收到的到底是個什么圖片。

這個圖片用戶那里雖然可以看,但是要生成到log里面就要另外保存一個文件,如果要上傳的話還要開發相應的圖片上傳功能,這就麻煩了。

當然還可以用eml或者mht的形式吧圖片打包在log里面,這樣圖片就會以base64形式編碼進去嵌在log的文本里面了。但是hta記得似乎控制save命令的時候不能制定mht格式(沒試過),eml要依賴客戶端有郵件客戶端,還要能通過js操控,更麻煩。

因此最簡單的看起來就是zishun寫的《利用HTML5對文件進行base64轉換》方案了,只要把圖片轉成DATAURI,就可以很容易的把圖片信息嵌入到頁面里面并在現代瀏覽器里面展現。這個方案唯一的問題是,僅限非IE。

還好IE其實也有類似的功能,并且效率更高,唯一的問題是要依賴activex,不過這再hta里面就不算問題了。

IE下的圖片文件(圖片)base64編碼代碼是這樣的:

<SCRIPT LANGUAGE="JavaScript">
<!--
var x= new ActiveXObject("Msxml2.XMLHTTP.6.0");
x.onreadystatechange
=function(){
    
if(x.readyState<4)return;
    
var xml_dom = new ActiveXObject("MSXML2.DOMDocument"); 
    
var tmpNode = xml_dom.createElement("tmpNode"); 
    tmpNode.dataType 
= "bin.base64"
    tmpNode.nodeTypedValue 
= x.responseBody; 
    base64string
=tmpNode.text.replace(/\n/g,"");
    document.write(
"<img src=\"data:image/bmp;base64,"+base64string+"\">")

}
x.open(
"get","http://www.qpkxbc.shop/images/blogjava_net/emu/1359/o_emu120.jpg",true);
x.send(
"");
//-->
</SCRIPT>




emu 2011-08-28 12:11 發表評論
]]>
Mac os 10.7.1(Lion) 下vmware fusion里的windows有時無法工作在NAT模式下的問題http://www.qpkxbc.shop/emu/archive/2011/08/27/357399.htmlemuemuSat, 27 Aug 2011 05:49:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/08/27/357399.htmlhttp://www.qpkxbc.shop/emu/comments/357399.htmlhttp://www.qpkxbc.shop/emu/archive/2011/08/27/357399.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/357399.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/357399.html因為mac系統很穩定,很少需要啟動,因此折騰很久都沒想到這中windows年代最順理成章的解決方式。

emu 2011-08-27 13:49 發表評論
]]>
IE這個bug真是弱爆了http://www.qpkxbc.shop/emu/archive/2011/08/08/355989.htmlemuemuMon, 08 Aug 2011 01:54:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/08/08/355989.htmlhttp://www.qpkxbc.shop/emu/comments/355989.htmlhttp://www.qpkxbc.shop/emu/archive/2011/08/08/355989.html#Feedback3http://www.qpkxbc.shop/emu/comments/commentRss/355989.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/355989.html<HTML>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
var a="<!--";
alert(a);
</SCRIPT>
<!--  -->
</BODY>
</HTML>
這樣一段代碼在IE下面居然語法解析錯誤!實在是弱到不知道怎么說好了。
當然,下面這一段代碼,也不出意外的在IE下掛掉了
<HTML>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
var a="<!--";
alert(a);
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
var a="-->";
alert(a);
</SCRIPT>
</BODY>
</HTML>


終于明白為啥Editplus里面插入script標記的時候總是幫我加上 <!-- 和 //-->了,這倆貨還真不能隨便去掉。
<HTML>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
var a="<!--";
alert(a);
//-->
</SCRIPT>
<!--  -->
</BODY>
</HTML>

這個就沒事。


emu 2011-08-08 09:54 發表評論
]]>
腳本綁定回調增強版:備用url可以失敗重試http://www.qpkxbc.shop/emu/archive/2011/07/19/354660.htmlemuemuTue, 19 Jul 2011 12:50:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/07/19/354660.htmlhttp://www.qpkxbc.shop/emu/comments/354660.htmlhttp://www.qpkxbc.shop/emu/archive/2011/07/19/354660.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/354660.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/354660.html《腳本綁定回調》  進行了一些有趣的嘗試,這些嘗試現在在一些web產品中已經應用了好幾年了。這兩年隨著海外用戶的增多,用戶情況的復雜化,我們的服務部署也開始復雜化了,有一些用戶訪問A域名失敗,訪問B域名就可能很暢順,另一些用戶則相反。而且很多時候這并不是gslb這樣的調度可以及時檢測到和快速調整的,不由得想想,能不能進行失敗重試呢?其實也很簡單把4年前的代碼改了一改,做了一個原理性的實驗:

<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
var isIE = !!window.ActiveXObject;
var useFragment=false;
function loadjs(url,callback,errcallback,url2,url3){
    
if(isIE){
        
if(useFragment){
           
var df = document.createDocumentFragment();    
            df.visitCountCallBack 
= function(data){
                s.onreadystatechange
=null;
                df
=null;
                callback(data);
            }
            
var s = df.createElement("SCRIPT");
            df.appendChild(s);
            s.onreadystatechange
=function (ec,cb,u2,u3){
                
return function(){
                    
if(s.readyState=="loaded") {
                        s.onreadystatechange
=null;
                        df
=null;
                        
if(!u2){
                            ec();
                        }
else{
                            loadjs(u2,cb,ec,u3)
                        }
                    }
                }
            }(errcallback,callback,url2,url3)
            s.src 
= url;
        }
else{
            
var i=new ActiveXObject("htmlfile");
            i.open();
            i.parentWindow.visitCountCallBack
=function(i){
                
return function(d){
                    i.parentWindow.errcallback
=null;
                    i
=null;
                    callback(d);
                }
            }(i);
            i.parentWindow.errcallback
=function(ec,cb,u2,u3){
                
return function(){
                    i.parentWindow.errcallback
=null;
                    i
=null;
                    
if(!u2){
                        ec();
                    }
else{
                        loadjs(u2,cb,ec,u3)
                    }
                }
            }(errcallback,callback,url2,url3)
            i.write(
"<script src=\""+url+"\"><\/script><script defer>setTimeout(\"errcallback()\",0)<\/script>")
            
if(i)i.close();//如果數據被cache,運行到這一行的時候有可能回調已經完成,窗口已經關閉。
        }
    }
else{
        
var i = document.createElement("IFRAME");    
        i.style.display
="none";
        i.callback
=function(o){
            callback(o);
            i.contentWindow.callback
=null;
            i.src
="about:blank"
            i.parentNode.removeChild(i);
            i 
= null;
        };
        i.errcallback 
= function(ec,cb,u2,u3){
            
return function(){
                    
if(!u2){
                        ec();
                    }
else{
                        loadjs(u2,cb,ec,u3)
                    }
            }
        }(errcallback,callback,url2,url3);
        i.src
="javascript:\"<script>function visitCountCallBack(data){frameElement.callback(data)};<\/script><script src='"+url+"'><\/script><script>setTimeout('frameElement.errcallback()',0)<\/script>\"";
        document.body.appendChild(i);
    }
}

function init(){
    
var spans = document.getElementsByTagName("span");
    
for(var i=0;i<spans.length;i++){
        
var id = spans[i].id;
        
var url = "http://g.qzone.qq.com/fcg-bin/cgi_emotion_list.fcg?uin=a"+id;//故意制造錯誤引發重試
        var url2 = "http://g.qzone.qq.com/fcg-bin/cgi_emotion_list.fcg?uin=b"+id;//故意再次制造錯誤引發重試
        var url3 = "http://g.qzone.qq.com/fcg-bin/cgi_emotion_list.fcg?uin="+id;
        
var callback = function(id){ return function(data){
            document.getElementById(id).innerHTML 
= data.visitcount;
            }
        }(id);
        
var errcallback = function(id){ return function(){
            document.getElementById(id).innerHTML 
= "無法連接到服務器";
            }
        }(id);
        loadjs(url,callback,errcallback,url2,url3);
    }
}
</SCRIPT>
</HEAD>
<BODY onload="init()">
12345(非法帳號)的訪問量:
<span id="12345"></span><BR>
123456 的訪問量:
<span id="123456"></span><BR>
20050606 的訪問量:
<span id="20050606"></span><BR>
</BODY>
</HTML>

故意在前兩次請求中制造了錯誤,嘗試到第三個url的時候才成功。

emu 2011-07-19 20:50 發表評論
]]>
把css和js寫到一個文件里面的增強版http://www.qpkxbc.shop/emu/archive/2011/07/19/354642.htmlemuemuTue, 19 Jul 2011 08:12:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/07/19/354642.htmlhttp://www.qpkxbc.shop/emu/comments/354642.htmlhttp://www.qpkxbc.shop/emu/archive/2011/07/19/354642.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/354642.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/354642.html原文鏈接

最早的方法發表在msdn上:
http://blogs.msdn.com/b/shivap/archive/2007/05/01/combine-css-with-js-and-make-it-into-a-single-download.aspx


代碼是像這樣子的:
<!-- /*
function test(){}
<!-- 
*/
<!-- body { background-color: Aqua; }

可是這樣css就必須要全部放到一行里面了。我做了一點點小修改來試圖可以合并多行的css或者多個css的內容進去:
<!-- /*
setTimeout('document.body.innerHTML="<span>Hello World</span>"',0);
<!-- 
*/
<!-- emu{emu:"\
/*
"}
span { background
-color: #f00; }
span { color: #0ff; }
/* */

這樣對于css來說,只是多了一個無用的規則 emu:{emu:"/*"}
而對于js來說,多了一行內容為 <!-- emu{emu:"\ 的注釋,以及一大塊/*開始的,包含了所有css內容的注釋。
IE9、Firefox5、safari5、chrome14下通過。沒裝opera,不是太關心這貨。
 

emu 2011-07-19 16:12 發表評論
]]>
怎么知道頁面被放大縮小了http://www.qpkxbc.shop/emu/archive/2011/06/23/352894.htmlemuemuThu, 23 Jun 2011 11:20:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/06/23/352894.htmlhttp://www.qpkxbc.shop/emu/comments/352894.htmlhttp://www.qpkxbc.shop/emu/archive/2011/06/23/352894.html#Feedback6http://www.qpkxbc.shop/emu/comments/commentRss/352894.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/352894.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<BODY>
<div id="output"></div>
<SCRIPT LANGUAGE="JavaScript">
<!--
(
function(){
    window.onresize
=testZoom;
    
var _screenOriginalWidth=window.screen.width
    
function testZoom(){
        
if(window.screen.width<_screenOriginalWidth){
            document.getElementById(
"output").innerHTML="<br>放大啦";
        }
        
if(window.screen.width>_screenOriginalWidth){
            document.getElementById(
"output").innerHTML="<br>縮小啦";
        }
        _screenOriginalWidth
=window.screen.width
    }
})()
//-->
</SCRIPT>
</BODY>
</HTML>


emu 2011-06-23 19:20 發表評論
]]>
如何分析js代碼的運行路徑?http://www.qpkxbc.shop/emu/archive/2011/06/16/352445.htmlemuemuThu, 16 Jun 2011 09:38:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/06/16/352445.htmlhttp://www.qpkxbc.shop/emu/comments/352445.htmlhttp://www.qpkxbc.shop/emu/archive/2011/06/16/352445.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/352445.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/352445.html1 如果script是用src引入的,還要用xhr或者json方式來獲得text,可能還需要搭個后臺代理。
2 如果function是在命名空間的,可以直接遞歸for in命名空間去挖里面的public函數出來。
3 private的函數我看就算了,私有函數應該對自己負責,我們沒有必要非去整人家的私貨。


<HTML>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
function a(x,y,z){return b(x,y)*c(z)};
function b(x,y){return c(x)*c(y)};
function c(x){return x+x};


setTimeout(
"alert(a(1,2,3))",0)
//-->
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
<!--
(
function (){
    window._log
=[];
    
function obj2str(o){
        
var r = [];
        
if(typeof o =="string"return "\""+o.replace(/([\'\"\\])/g,"\\$1").replace(/(\n)/g,"\\n").replace(/(\r)/g,"\\r").replace(/(\t)/g,"\\t")+"\"";
        if(typeof o ==
"undefined") return "undefined";
        if(typeof o == 
"object"){
            if(o===null) return 
"null";
            else if(!o.length){
                for(var i in o)
                    r.push(i+
":"+obj2str(o[i]))
                r=
"{"+r.join()+"}"
            }else{
                for(var i =0;i<o.length;i++)
                    r.push(obj2str(o[i]))
                r=
"["+r.join()+"]"
            }
            return r;
        }
        return o.toString();
    }

    function log(s){
        _log.push(s);
    }
    var s=document.getElementsByTagName(
"SCRIPT")[0].text;
    var r=/function (\w+)\(/g;
    var fns=s.match(r);
    for(var i=0;i<fns.length;i++){
        fn=fns[i].replace(r,
"$1")
        if (typeof window[fn]==
"function"){
            window[fn]=(function(org,fn){
                return function(){
                    log(
"進入:"+fn+"\n調用參數:"+obj2str(arguments));
                    var r=org.apply(null,arguments);
                    log(
"退出:"+fn+"\n返回值"+obj2str(r));
                    return r
                }
            })(window[fn],fn)
        }
    }
})()
setTimeout(
"alert(window._log.join('\\n\\n'))",100)
//-->
</SCRIPT>
</BODY>
</HTML>


emu 2011-06-16 17:38 發表評論
]]>
IE6上Gzip+Etag問題的解決方案http://www.qpkxbc.shop/emu/archive/2011/02/27/345262.htmlemuemuSat, 26 Feb 2011 16:37:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/02/27/345262.htmlhttp://www.qpkxbc.shop/emu/comments/345262.htmlhttp://www.qpkxbc.shop/emu/archive/2011/02/27/345262.html#Feedback8http://www.qpkxbc.shop/emu/comments/commentRss/345262.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/345262.htmlhttp://www.qpkxbc.shop/emu/archive/2011/02/27/345262.html
  
      這個問題不是太廣為人知,但也算不上新鮮知識了,IE6如果接收到一個gzip壓縮的http響應,那么這個響應中的Etag信息會被拋棄,此時只能依賴last-modified時間來設計cache策略。某些類型的Vary值據說也會導致相同的問題。
        為了這個問題emu在http頭上動了n多手術,甚至把200響應狀態硬生生換成206等狀態,IE6一直都非常頑固的不肯吐出If-None-Match信息。幾乎要放棄了。
        丟開這個bug,我們來看問題的實質是什么。實質是,我們有一個叫做Etag的,響應內容的一個hash值,需要在響應的時候從服務器送給瀏覽器,并且要求在瀏覽器下次請求同一個路徑的時候把這個hash值送回給服務器校驗。http中規定了,我們可以在http header內容中通過一個叫做Etag的header來做這個事,但是現在瀏覽器不給力啊,有啥別的手段可以做相同的事情呢?

        答案一點也不難想,我們一天到晚在實現“把一個值從服務器送給瀏覽器,并讓瀏覽器吧它送回服務器”這件事的時候都是用什么手段的呢?沒錯啦,就是cookie。而且cookie還支持path!
        因此需要做的事情就是,server在發現User-Agent是IE6的時候,在返回gzip內容的時候出了要送Last-Modified時間之外,不要送Etag頭了,改為返回一個set-cookie頭:
        Set-Cookie: etag=hash; pagh=/mypath
        服務器在下次收到請求的時候,如果收到了If-Modified-Since信息,表明客戶端有一份當前請求的cache,就可以從cookie里面驗證etag值來決定是否返回304拉!


emu 2011-02-27 00:37 發表評論
]]>
Firefox的getter和setter帶來的安全隱患http://www.qpkxbc.shop/emu/archive/2011/01/19/343192.htmlemuemuWed, 19 Jan 2011 01:47:00 GMThttp://www.qpkxbc.shop/emu/archive/2011/01/19/343192.htmlhttp://www.qpkxbc.shop/emu/comments/343192.htmlhttp://www.qpkxbc.shop/emu/archive/2011/01/19/343192.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/343192.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/343192.html

   document.__defineGetter__(    
"cookie"
        
function(){ 
            
return this.c;
        } 
    ); 
    document.__defineSetter__(    
"cookie"
        
function(sText){ 
            
this.c="HACK : "+sText; 
        } 
    );     
   document.__defineGetter__(    
"domain"
        
function(){ 
            
return this.d;
        } 
    ); 
    document.__defineSetter__(    
"domain"
        
function(sText){ 
            
this.d="HACK : "+sText; 
        } 
    );     
    document.cookie
="fake cookie";
    alert(document.cookie)
    document.domain
="fake domain"
    alert(document.domain)


document實際上已經成了一個傀儡,隨便開發者擺弄了。因此我們做基于document.domain和document.cookie的一些對第三方判斷時候要小心。

emu 2011-01-19 09:47 發表評論
]]>
好像是第一次在公司外的論壇上公開演講http://www.qpkxbc.shop/emu/archive/2010/12/15/340824.htmlemuemuWed, 15 Dec 2010 12:43:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/12/15/340824.htmlhttp://www.qpkxbc.shop/emu/comments/340824.htmlhttp://www.qpkxbc.shop/emu/archive/2010/12/15/340824.html#Feedback4http://www.qpkxbc.shop/emu/comments/commentRss/340824.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/340824.html    終于講完了,下午公司內進行了二次分享,應該這次的分享算功德圓滿了。
    國慶剛回來,淘寶就透過yuni吹風過來,說velicity會議第一次在國內舉行,希望我們去參與和分享。幾乎是本能的想逃了,實在不知道站到那樣一群完全陌生的人前面,要講些什么,怎么講。
    到了10月底,dowson老大安排下來了,要去講一場,這下躲不掉了,只好開始琢磨。看了下velocity在美國的分享PPT,偏web前端,偏性能和體驗優化,而且都是很實用的技術。話題倒是熟悉,但是考慮到去的都是很多標桿公司,大家做的事情都差不多,如果講別人做過和正在做的事情,那就沒意思了。所以現狀就是,要發掘些別人沒想到的、行之有效的優化點去分享一下。
    當時本來也在公司內試推錯峰preload方案,技術上都ok了,效果相當給力,想法也夠新穎。本來有點想藏私的,leichen和dowson都主張我們要更開放點,就決定放出來了。
    然后再發掘我們內部獨創的秘籍,有一些已經用爛了,有一些優化點又太小,顯得小家子氣,都否決了,最后選中了用了好幾年,比較穩定可靠,外面又還沒怎么聽說過的ldns域名矯正方案。
    隨后就爆發了那場大家都知道的大戰,公司在很多專業人士眼里的形象好像都有點變型了,也感覺到我們做的很多正面的事情太低調了,不為人知。講點啥能又有用,又能改變在大家心中的負面形象呢?正好這一年比較關注信息無障礙,于是確定了第三個議題。
    接著就是準備PPT和演講內容。還好上次參加BU技術峰會學習到一個很重要的經驗,一個PPT只要反復改,自然會慢慢變好。于是確定了主體內容,先是做了個和word差不多的PPT,然后不停的設想,講這個內容要怎么講,哪些意思要怎么表達,用什么圖案,用什么動畫效果,說些什么話。以前內部審核了很多課程的經驗,也起了很大作用。中間還產生了不少創意,比如現場發禮品,拍團隊視頻等,有一些后來用上了,一些就放棄了。這是個不錯的廣告機會,又找great制作了春田花花同學會的logo作為幻燈片母版,這樣就不動聲色的打了一小廣告。為了方便老大審核,把要說的話都提前設計好放到備注里面去了。這樣也好,不怕到時忘詞了,這是有深刻的歷史教訓的。設計了兩周,才終于敢發給dowson審核。dowson給了一些修改意見,接著改。
    然后就是約了研發管理部,打算用敏捷俱樂部或者大講堂作為內部試講。但是沒想到約的太晚,居然沒有辦法在velocity之前講。好吧,先拿velocity做試講,呵呵當然不可能了,只能內部試講。一直拖著直到最后一個周五,再也沒法拖了,才把前端team的兄弟們拉過來聽試講。
    試講真的很重要,試講一遍暴露了很多問題,也收集到了很多改進建議。周末回家后接著改,改了以后投影到液晶電視上,自己對著一空沙發試講,講到哪里卡殼了又停下來,把內容理順,慢慢的內容越來越順了,又開始刪除備注里面的文字,看看自己能不能記得住詞。到嗓子啞的時候,終于有一點感覺了。想用相機錄下來自己看一遍,沒想到一對著鏡頭,立馬就忘詞,三番四次之后,相機也沒電了,就作罷了,希望到時在現場不要像對著這個相機這么緊張就好了。
    到北京的兩天,都專心聽別人演講,沒怎么想起自己要講的事情,到最后一天下午,終于丑媳婦要見公婆了,又覺得內容有點陌生了,還好是下午第三場,利用中午的時間又過了一下內容,還修改了下ppt。接下去,不想了,準備上場。
    辛苦的準備終于還是換來了回報。現場沒怎么忘詞,而且講的太嗨了,忘了控制時間,小馬提前過來打手勢的時候才想起來。后面的內容趕了下時間,一些想好的臺詞和內容都跳過了,比如和視障用戶交流的一些細節,在3q大戰中視障用戶的支持等。
    一開始講的時候提到了兩次steve souders,隨后才看到他進場來聽,呵呵可惜了,本來我的內容里面估計也只有他自己的名字他能聽懂,他居然錯過了。還好后面幾次提到google,gmail,還有很多代碼和圖案,他居然一句話沒聽懂也津津有味的聽完了。隨后他還跑過來祝賀我,說我good work。我說你聽得懂嗎,他說聽不懂,我就樂了,聽不懂你good work個啥啊,他說,the audience。我當時確實有點不以為然了。
    沒想到后來又再專門找到我,跟我解釋,說我是真的從聽眾的反應中可以看到你good work。后來他回到米國后發了一篇博客http://www.stevesouders.com/blog/2010/12/10/velocity-china/comment-page-1/ ,提到“I had trouble following the talks that were only in Chinese although slides that had code or charts are universal. But I could tell these were good speakers – they were at ease up on stage, they engaged the audience, and their slides looked good.”,呵呵,還好聽眾們給力,還好我往PPT上放了好些charts和code。

開講
和老道合影

和steve souders合影



emu 2010-12-15 20:43 發表評論
]]>
信息無障礙的修復腳本http://www.qpkxbc.shop/emu/archive/2010/09/26/332999.htmlemuemuSun, 26 Sep 2010 13:37:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/09/26/332999.htmlhttp://www.qpkxbc.shop/emu/comments/332999.htmlhttp://www.qpkxbc.shop/emu/archive/2010/09/26/332999.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/332999.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/332999.html onfocus="this.blur()"
這樣就導致整個網站人為的變成有障礙網站了,任何無法使用鼠標的用戶也就無法正常使用這個網站,因為鍵盤不能聚焦到超鏈接上。
修復這個問題很簡單,用hideFocus或者style="outine:none"來代替onfocus="this.blur()"就好了,但是有的時候網站頁面太多,全站修改代價就大了。這種情況下可以在網站的模板或者通用腳本上面插入以下一段腳本來解決問題:

setTimeout(
    (
function(){
         
var a=document.getElementsByTagName("A");
         
var regBlur=/^function ((anonymous)|(onfocus))?\((event)?\)\s*\{\s*(this\.)?blur\(\);?\s*\}$/;
         
var isIE=("\v"=="v");
         
for(var i=0;i<a.length;i++){
             
if(regBlur.test(a[i].onfocus)){
                 
if(isIE){
                      a[i].hideFocus
="true";
                 }
else{
                      a[i].style.outline
="none"
                 }
                 a[i].onfocus
=null;
             }
         }
    }),
1000)

是不是很簡單啊。
這段代碼對于opera瀏覽器不兼容,因為opera瀏覽器本身就不是一個信息無障礙的瀏覽器,沒有視障用戶用opera的,大家都來鄙視opera吧。

平安夜那天早上,晴天反饋說有一些網站不是直接寫onfocus事件,而是用attachEvent/addEventListener方式寫了惡心的this.blur()。這事咋整呢?沒有拿到原來綁定上面的函數句柄,就不能detachEvent啊。最終想了一個跟blur差不多一樣惡心的hack:
<html>
 <head>
 
<body>
  
<href="#" onclick="alert('click1')">test1</a>
  
<href="http://www.qq.com/" >qq</a>
  
<href="http://www.baidu.com/" >baidu</a>
  
<script type="text/javascript">
  
<!--
    
var ls=document.links;
    
//這是原來讓鏈接不能聚焦的代碼
    for(var i=0;i<ls.length;i++){
        ls[i].attachEvent(
"onfocus",function(){this.blur()})
    }
    
//這是讓鏈接重新可以聚焦的代碼
    for(var i=0;i<ls.length;i++){
        
var a=document.createElement("A");
        a.innerHTML
=ls[i].innerHTML;
        ls[i].innerHTML
="";
        ls[i].appendChild(a);
        a.tabIndex
=0;
        ls[i].tabIndex
=-1;
    }

  
//-->
  </script>
 
</body>
</html>

這樣可以解決大部分類似這樣的問題,也可以代替上面的方案,不過有一些副作用。考慮到大多數情況下超鏈接標簽內部的內容結構都比較簡單,也不會有太多的內部事件綁定的情況,這段代碼應該可以應付大多數情形了。

emu 2010-09-26 21:37 發表評論
]]>
iPad驚魂http://www.qpkxbc.shop/emu/archive/2010/06/26/324552.htmlemuemuSat, 26 Jun 2010 06:05:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/06/26/324552.htmlhttp://www.qpkxbc.shop/emu/comments/324552.htmlhttp://www.qpkxbc.shop/emu/archive/2010/06/26/324552.html#Feedback3http://www.qpkxbc.shop/emu/comments/commentRss/324552.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/324552.html事后彪叔是這么評價的:“那些小偷也倒霉,搶個東西遇到深圳反扒隊的。。。”。


6月11號

  • WWDC2010的最后一天。早上在web開發方面還有最后兩個repeat的session,是Nob Hill會議室的《Delivering Audio and Video Using Web Standards》。聽完后覺得,所有的演示都基于局域網內非常快速的網絡速度,如果網絡差的地方,會不會和那天Jobs演示的時候一樣,一下就杯具了呢?于是和蘋果的工程師探討了一下,在網絡很差的時候能不能用腳本對音視頻的緩沖進行更進一步的控制,以達成更好的效果。蘋果的工程師回答是你可以用腳本控制buffer,不過還是覺得存疑了,沒有試驗環境也不好進一步探討,算了,回來自己研究。


    (WWDC2010會場)

  • session結束后,中午還有個CNN的event。聽完后決定和wang一起去金門大橋看看夕陽,來了這么多天還沒去過呢。于是坐上了38L路公交車前往金門大橋。在車上忍不住又把iPad拿出來繼續讀沒看完的rss feeds。車子沿著geary大街走,在polk和van ness街之間有個站,有很多人排隊下車。


    (CNN的技術VP在演講的時候喜歡放很多震撼畫面)

  • 這個時候有個中等個子的黑人小伙慢騰騰的排著隊從我面前經過,突然一伸手,搶了我的iPad就往車下跑。好家伙,公車搶奪,原來在舊金山也和在國內并無二致。我跳起來一伸手抓住黑人的夾克衣領往后一扯。不幸的是體重對比太懸殊了,自己反而被他帶到車下來了。


    (車票)

    嗯,在這里要再三強調一下,本人接受過一段時間的自衛術訓練,包括如何在這樣的情形下與身材比自己大一圈的對手搏斗,我們都是有過若干預案的,比如偷襲(第一預案,當時不具備這個條件);尋找手持武器自衛(第二預案,除了被搶去的iPad,手里只剩一個單反相機了,作為攝影協會老會員,這個預案也必須否決);裝瘋(撲上去大喊大叫亂打一氣,逮到機會就抱緊對手狠咬一口,從氣勢上嚇懵對手————考慮到自己門牙打過補丁,咬人這招不到萬不得已不用)。圍觀群眾切勿效仿。


    (iPad確實是現在最好玩的成人玩具)

  • 于是采用了裝瘋預案,我一邊大聲不知道喊著啥,一邊左手緊抓著對方的衣領,跟他貼身,讓他右手被欄到我外面不能攻擊我(期望他是右撇子),右手開始用力打他的胸腹部。他也用左手還擊我。一個不小心,兩個人都絆倒了。杯具了,他倒在我身上,我翻不過去,被他騎住了。于是我只好兩只手都收回來,準備在他攻擊的時候可以做保護動作,此時真正有點危險了,不料對方一發現這個瘋子松手,立刻抓住機會瘋狂逃竄。萬幸。
    打斗太激烈,感覺到全身脫力,我繼續在地上躺了幾秒鐘緩下勁。wang同學大概就是這個時候認為我被打懵了,呵呵。然后起身來檢查一下,沒有大礙,看看身邊,iPad已經被摔碎了,可憐的小家伙。


    (iPad成這樣了)

  • 這個時候的標準操作應該是等警察到場處理,不過我的護照和電腦都還在公車上,要是護照丟了問題就嚴重了,只好先回車上拿包。拿到包后心寬了一點,終于可以坐下來透口氣了,沒想到公車這時發動了,開往下個站,我只好安心在車上休息一下,順便自拍一張看看臉上那里刮破了。

  • 坐了一會,和wang商量了一下,還是不去金門大橋了,于是下車去報案。很多國內的朋友英文聊天還可以,最怕就是和外國人打電話,聽半天聽不清楚,其實大多數移民國家的公眾服務部門都有提供多語言的翻譯服務的,在這種復雜情形下更沒有必要去考驗自己的英文水平。打通了911后,我直接就要求了中文翻譯服務。在翻譯到達之前和警官溝通了一下基本情情況,然后接下去就翻譯接手了。
  • 描述完現場情形,警方問要不要派救護車。自己也是擔心有內傷,去查一下也好,就讓派了一個。911要求,在原地等候救護車和警察到場,在完成檢查之前不可以喝水吃東西(怕有內傷會惡化)。如果外傷流血不止的話他們可以在電話里面提供緊急止血指導————此時我的血已經止住了。然后開始等救護車。

  • 等了不知道多久,越來越口渴,又打了一個911,對方說救護車已經在路上,請繼續耐心等候。繼續等吧。然后就看到在對面路口發生了一起斗毆事件,終于把警察吸引過來了。我于是過街給警察當面再報一次案。


    (對面的美國人民打成一片)

  • 女事主很郁悶,要求警察先處理她的事,警察指著我額頭的傷口說,他傷的比你嚴重,所以要先處理他的。呵呵報案原來也有插隊的。

  • 于是重新描述了一遍事情經過,警察通過對講機呼叫了一番后,救護車終于姍姍來遲了。從來沒躺過擔架的,這下也體驗到了。

  • 上救護車后,先等警察完成報案手續(也許還順便驗證一下我的護照號有沒有登記案底?),把證件和我的案件case No給我。


    (案件編號)

  • 之后我先要求護士幫我聯系保險公司。出門前特地把平安的海外聯系電話存在了手機里面應急的,這下可以用上了吧?護士詢問了保險公司的名稱后去系統里面查了一下,后來好像查不到“Ping An”這個公司,就先不管了,有什么費用等事后再找保險公司也可以的。


    (救護車內照片)

  • 送進醫院以后,就不允許動相機了:((


    (病房內偷拍)

  • 醫院的人都很友好,處理我這個case的醫生護士幾乎每個人都來問了一下我的情況,還有從哪里來的,然后表達一下同情,最后再welcome to CA或者welcome to SF,盡力在使我覺得自己是被關心,受重視并且受到歡迎的。

    (醫院給病人套一個腕帶,把我的名字拼錯了。把寫在名字前面的visa的issue place當成first name了)

  • 一個很瘦小的東方面孔的美女醫生負責處理我的case。詢問了一下發生什么事,在我身上各個可能受傷的位置擠按拍打,確定重點檢查部位,問了一些藥物過敏和近期服用藥物的問題,太專業了,我的英文又不夠用了。問我說哪種中文,我說普通話,然后就杯具了,等說普通話的醫生等了好久,還是沒等到。


    (處方)

  • 最后拉了香港醫生阿May過來,問我能不能說廣東話,我說也可以啊,醫生也快崩潰了————怎么不早說。之后的溝通簡單多了,可以用廣東話。


    (醫囑)

  • 阿May把我扶上輪椅,推過去拍了兩張X光,再推回來等結果。阿May悄悄跟我說,也不用聯系我保險公司了,費用讓受害人基金會出就好了。也是啊,在加州隨便買點啥都要收我那么多稅,搞了半天社會治安還這么差,施瓦辛格的這個錢當然不能幫他省了。我這時都快渴死了,還是不能喝水,繼續忍著。


    (胸透X光片)

  • 忍到結果出來,好幾張專業文檔,關鍵內容好像都是我看不懂也聽不懂的。阿May好像下班了,于是護士小姐又打了個三方通話的翻譯服務電話,給我介紹我的情況:肋骨骨折。我嚇了一大跳,讓翻譯再確認一下,是不是我們通常理解的骨折,護士很確定的說,骨折了,不需要特殊處理,幾周就自愈了,這期間要用力深呼吸擴張胸部,對愈合有好處。如果骨折影響了呼吸,那就吃止痛藥,然后繼續用力深呼吸。


    醫生好心要把一份文檔打印成中文的給我看,:((

  • 掛了電話,我讓護士再去問醫生,我哪個骨頭折了。醫生過來給我說,右側第8或者第9,輕微骨折。杯具了。
    給了我一個止痛藥讓我服下,然后給我一個止痛藥處方讓我自己去買其中的某一種止痛藥。然后,我可以自己回酒店了,呵呵,這是給骨折病人的待遇嘛。


    (復診提示)


    (醫院只開方不賣藥,但是對處方中的藥物卻提供了通俗易懂的說明。)


    (醫院只開方不賣藥,但是對處方中的藥物卻提供了通俗易懂的說明。)

  • 回到酒店,先上網,第一時間發微博消息。呵呵,信息時代啊。


    (回酒店第一時間發微博。這是舊金山時間11日晚上。)

  • 出去吃了個飯,買了瓶布洛芬回來,發現騰訊數碼微博已經推了這個消息,騰訊網友已經在微博上回復不少消息了。有網友建議可以拿iPad去蘋果店看看能不能修,我本來想著肯定不能修了,不過去看看也好。有很多網友質疑一臺iPad值得這樣冒險嗎?這樣冒險和黑人壯漢搏斗當然不是為了一臺iPad這么簡單,我嘗試了在微博上解釋一下,不過這真的對大家來說不是太好理解,算了。


    (微博截屏)

  • 也有網友說可以找jobs要臺新的。呵呵,喬幫主前幾天剛講過個故事說有個小伙玩iPad吸引到了美女注意,我要是這事寫封伊妹兒給喬幫主說說說,讓他下回要說這事也順便提醒一下大家iPad的魔力也會帶來為危險,倒是不錯。于是寫了第一封信。這一天就算過去了。


    (微薄截屏)

    12號

  • 由于背部受傷,一個晚上無法翻身,睡的相當別扭,一大早就起來了。一上線,正好有同事找我,說蘋果公司開發者關系部夏鵬正在設法聯系我,于是和他們聯系了一下,溝通了情況,夏鵬主動提出第二天送我去機場。完了帶著iPad的尸體前往蘋果店。

    (iPad尸體)

  • 蘋果店的人看到iPad的尸體沒有期待的那么意外,很公事公辦的說要找工程師評估一下價格。過了一回評估價格出來了,維修費$269。又等了一下,大高個黑人工程師出來接待。一見面很例行公事的問了句how are you,我一下想起那個摔下山崖的中國留學生笑話呵呵,于是跟他講,不好,被人搶劫,iPad砸成了這樣,還把我打傷了(和警察講述的時候要盡量描述細節,和其他美國人講述的時候,卻要刻意回避搶劫者的膚色問題,種族歧視在西方國家是極其敏感的問題)。大高個聽到了以后一臉的心痛和惋惜的表情,換了個非常非常溫柔的聲音跟我說怎么會這樣,這不應該發生在你身上。你等等,我進去和主管商量一下,看看能不能免你的維修費。我很驚訝,他們看起來完全沒必要給我這樣的優待啊。大高個說機器砸爛了不是你的錯,看看你的傷口,壞人太壞了。
    趁著他們商量,我又用現場的mac上網發了兩條微博。結果他們很快就商量完了,大高個出來說,我們免費給你換了。拿出來一份換機文件給我簽署,然后從倉庫給我拿了臺新機出來。

    (換機協議)

     

  • 這真是意外之喜,我道了謝就走了,走出了好遠才想起來,怎么沒和大高個合個影,又回去找他合影。

    (網友普遍認為這個apple guy很帥)

  • 回到酒店,又給喬幫主發了第二封郵件,對蘋果公司表示了一下感謝。后來很多人說蘋果一臺iPad就把我收買了。其實正是他們在表達關心和給予優待的時候的這種毫無目的,把我感動了一下。


    (第二封郵件)

  • 過了不久,居然收到了Jobs的那封只有3個單詞的回信。眾所周知喬布斯輕易不回郵件,以至于有些果粉網友說這封回信比若干臺iPad還有價值,還有很多人勸我打印裝裱起來供著,或者打印到衣服上天天穿著,呵呵。


    (喬幫主的回郵)

  • 數碼頻道及時推了這個消息之后,我得以有幸見識到喬布斯的魅力所在。中國開發者被襲擊的消息并沒有多少人關注,但是喬布斯給中國開發者發了郵件的消息,一下大小網站紛紛轉載,國外網站也出了新聞,連我在老家連喬布斯何許人都搞不清楚的父母,也很快就知道了這件事,為了免得他們擔心,我本來打算回國后再跟他們說的,這下瞞不住了。

    13號

  • 早上9點半,蘋果公司的陳梓橋和夏鵬準時到酒店來送我們去機場。



    (蘋果公司的陳梓橋和夏鵬)

    14號
    早上把美國拍片的結果發給馬醫生看,馬醫生初步認為8、9肋骨輕微骨折,無錯位。7肋骨可疑。
    下午重新排了片,劉主任分析結果,骨頭問題不大,主要是軟組織拉上,開了些中藥,建議靜養幾天。



  • emu 2010-06-26 14:05 發表評論
    ]]>
    弱視用戶看到我們的頁面是像這樣的http://www.qpkxbc.shop/emu/archive/2010/06/22/324139.htmlemuemuTue, 22 Jun 2010 03:33:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/06/22/324139.htmlhttp://www.qpkxbc.shop/emu/comments/324139.htmlhttp://www.qpkxbc.shop/emu/archive/2010/06/22/324139.html#Feedback4http://www.qpkxbc.shop/emu/comments/commentRss/324139.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/324139.html看了蘋果WWDC的無障礙設計部分,他們的開發人員就是這樣來體驗弱視用戶的產品體驗的,我們也來體驗一下別人的痛苦吧。我們的頁面有辦法設計得讓這群人也感受好一點嗎,就像蘋果正在做的



    emu 2010-06-22 11:33 發表評論
    ]]>
    不可忽略的 cache-read time(緩存讀取延遲時間) 瓶頸http://www.qpkxbc.shop/emu/archive/2010/04/09/317898.htmlemuemuFri, 09 Apr 2010 14:58:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/04/09/317898.htmlhttp://www.qpkxbc.shop/emu/comments/317898.htmlhttp://www.qpkxbc.shop/emu/archive/2010/04/09/317898.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/317898.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/317898.html小小和rizen嘗試過定位一個cache-read耗費時間隨機的變得很長的詭異問題,排除過了文件內容、文件類型、文件頭等各種影響,但是很遺憾沒有最終結論。emu那天看知道這個事情后猜測,會不會就是很簡單的多個cache-read操作相互競爭堵塞導致的呢?這個其實很容易驗證了。寫了一個簡單的小頁面應用了一組圖片,然后抓包重新打開頁面,就看到下面這個圖了:




    第一個cache-read耗時0.2秒多,第二個(并行發起)0.3秒多,第三個0.4秒多,接下去每個圖片的耗時差不多都比上一個慢0.1秒以上。結論很明顯了,并發的cache-read會相互堵塞,非常嚴重的相互堵塞。
    以上抓包是在IE6下完成的。在IE7和IE8下面情況要好一些,但是問題性質是相同的。
    很多我們曾經以為cache的非常好速度應該非常快的web應用,也許其實存在著嚴重的cache-read速度瓶頸而不為我們所知。
    網上沒有搜到太多關于cache-read時間的文章,看來真是個盲點。

    解決方案和網絡延遲是類似的,減少cache-read請求,把多個小文件和小圖片合并成大文件和大圖片(而不要一廂情愿的以為小文件被瀏覽器緩存后會有很好的速度表現),區分優先級引用資源。還有一個可能有用的:交錯的發起不可避免的異步動態網絡請求和cache-read請求,讓網絡延遲和cache-read延遲時間疊加在一起,來節省用戶實際要等待的時間。



    emu 2010-04-09 22:58 發表評論
    ]]>
    IE6不能用gzip壓縮腳本,一個流毒甚廣的謠言http://www.qpkxbc.shop/emu/archive/2010/03/31/317027.htmlemuemuWed, 31 Mar 2010 03:37:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/03/31/317027.htmlhttp://www.qpkxbc.shop/emu/comments/317027.htmlhttp://www.qpkxbc.shop/emu/archive/2010/03/31/317027.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/317027.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/317027.html  

    文章作者說“跑到微軟那一查,給的答復讓我吐血:Do not enable HTTP compression for the script files 請不要對腳本文件開啟http壓縮 只好在服務器端增加對瀏覽器的識別代碼,如果是ie6,就不壓縮腳本文件了 雖然腳本能運行了,可是用戶體驗就...  哎,我恨ie 6”

    唉,說啥好呢?

    真相是,微軟的答復(http://support.microsoft.com/kb/327286/en-us?sid=64&spid=2073) 里面提供了兩個解決方案,其中第一個描述的稍微啰嗦了一點,被這個作者直接忽略掉了。第二個解決方案只有一句話,顯然更容易被讀懂:

    To work around this problem, you can do either of the following:

    If you use a Cache-Control: no-cache HTTP header to prevent the files from caching, remove that header. In some situations, if you substitute an Expires HTTP header, you do not trigger the problem.

    -or-

    Do not enable HTTP compression for the script files.


    Emu雖然英文比較爛,四級老考不過,為了方便大家還是翻譯一下吧,不然又該有人讀不下去了。

      要規避此問題,你可以在下面兩個方案中選一種:

        1.如果你使用了Cache-Control: no-cache 這個 HTTP 頭來防止文件被緩存,移除這個頭就好了。有些情況下,如果你用一個Expires頭來代替(前面這個出問題的http頭),(也可以起到相同作用而)不會觸發這個問題。

        或者

        2.不要壓縮腳本文件。

    個人建議還是考慮第一方案。

    本文作為前面一篇翻譯文章《壓縮,讓網絡更快》的補充。

    emu 2010-03-31 11:37 發表評論
    ]]>
    [翻譯]加速Javascript:DOM操作優化http://www.qpkxbc.shop/emu/archive/2010/03/01/314185.htmlemuemuMon, 01 Mar 2010 09:20:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/03/01/314185.htmlhttp://www.qpkxbc.shop/emu/comments/314185.htmlhttp://www.qpkxbc.shop/emu/archive/2010/03/01/314185.html#Feedback4http://www.qpkxbc.shop/emu/comments/commentRss/314185.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/314185.html原文:《Speeding up JavaScript: Working with the DOM》

    作者: KeeKim Heng, Google Web Developer

    在我們開發互聯網富應用(RIA)時,我們經常寫一些javascript腳本來修改或者增加頁面元素,這些工作最終是DOM——或者說文檔對象模型——來完成的,而我們的實現方式會影響到應用的響應速度。

    DOM操作會導致瀏覽器重解析(reflow),這是瀏覽器的一個決定頁面元素如何展現的計算過程。直接修改DOM,修改元素的CSS樣式,修改瀏覽器的窗口大小,都會觸發重解析。讀取元素的布局屬性比如offsetHeithe或者offsetWidth也會觸發重解析。重解析需要花費計算時間,因此重解析觸發的越少,應用就會越快。

    DOM操作通常要不就是修改已經存在的頁面上的元素,要不就是創建新的頁面元素。下面的4種優化方案覆蓋了修改和創建DOM節點兩種方式,幫助你減少觸發瀏覽器重解析的次數。

    方案一:通過CSS類名切換來修改DOM 

    這個方案讓我們可以一次性修改一個元素和它的子元素的多個樣式屬性而只觸發一次重解析。

    需求:

    (emu注:原文作者寫到這里的時候腦子顯然短路了一下,把后面的Out-of-the-flow DOM Manipulation模式要解決的問題給擺到這里來了,不過從示范代碼中很容易明白作者真正想描述的問題,因此emu就不照翻原文了)

    我們現在需要寫一個函數來修改一個超鏈接的幾個樣式規則。要實現很簡單,把這幾個規則對應的屬性逐一改了就好了。但是帶來的問題是,每修改一個樣式屬性,都會導致一次頁面的重解析。

    function selectAnchor(element) {
      element.style.fontWeight 
    = 'bold';
      element.style.textDecoration 
    = 'none';
      element.style.color 
    = '#000';
    }

     

    解決方案

    要解決這個問題,我們可以先創建一個樣式名,并且把要修改的樣式規則都放到這個類名上,然后我們給超鏈接添加上這個新類名,就可以實現添加幾個樣式規則而只觸發一次重解析了。這個模式還有個好處是也實現了表現和邏輯相分離。


     

    .selectedAnchor {
      font
    -weight: bold;
      text
    -decoration: none;
      color: #
    000;
    }

    function selectAnchor(element) {
      element.className 
    = 'selectedAnchor';
    }

    方案二:在非渲染區修改DOM

    (emu注:作者在這里再次腦子短路,把DocumentFragment DOM Generation模式的介紹提前到這里來了,emu只好再次發揮一下)
    上一個方案解決的是修改一個超鏈接的問題,當一次需要對很多個超鏈接進行相同修改的時候,這個方案就可以大顯身手了。

    需求

    需求是這樣的,我們要寫一個函數來修改一個指定元素的子元素中所有的超鏈接的樣式名(className)屬性。要實現很簡單,我們可以通過遍歷每個超鏈接并且修改它們的樣式名來完成任務。但是帶來的問題就是,每修改一個超鏈接都會導致一次重解析。

    function updateAllAnchors(element, anchorClass) {
      
    var anchors = element.getElementsByTagName('a');
      
    for (var i = 0, length = anchors.length; i < length; i ++) {
        anchors[i].className 
    = anchorClass;
      }
    }

    解決方案

    要解決這個問題,我們可以把被修改的指定元素從DOM里面移除,再修改所有的超鏈接,然后在把這個元素插入回到它原來的位置上。為了完成這個復雜的操作,我們可以先寫一個可重用的函數,它不但移除了這個DOM節點,還返回了一個把元素插回到原來的位置的函數。

    /**
     * Remove an element and provide a function that inserts it into its original position
     * @param element {Element} The element to be temporarily removed
     * @return {Function} A function that inserts the element into its original position
     *
    */
    function removeToInsertLater(element) {
      
    var parentNode = element.parentNode;
      
    var nextSibling = element.nextSibling;
      parentNode.removeChild(element);
      
    return function() {
        
    if (nextSibling) {
          parentNode.insertBefore(element, nextSibling);
        } 
    else {
          parentNode.appendChild(element);
        }
      };
    }

    有了上面這個函數,現在我們就可以在一個不需要解析渲染的元素上面修改那些超鏈接了。這樣只在移除和插入元素的時候各觸發一次重解析。
    function updateAllAnchors(element, anchorClass) {
      
    var insertFunction = removeToInsertLater(element);
      
    var anchors = element.getElementsByTagName('a');
      
    for (var i = 0, length = anchors.length; i < length; i ++) {
        anchors[i].className 
    = anchorClass;
      }
      insertFunction();
    }

    方案三:一次性的DOM元素生成

    這個方案讓我們創建一個元素的過程只觸發一次重解析。在創建完元素以后,先進行所有需要的修改,最后才把它插入到DOM里面去就可以了

    需求

    需求是這樣的,實現一個函數,往一個指定的父元素上插入一個超鏈接元素。這個函數要同時可以設置這個超鏈接的顯示文字和樣式類。我們可以這樣做:創建元素,插入到DOM里面,然后設置相應的屬性。這就要觸發3次重解析。

    function addAnchor(parentElement, anchorText, anchorClass) {
      
    var element = document.createElement('a');
      parentElement.appendChild(element);
      element.innerHTML 
    = anchorText;
      element.className 
    = anchorClass;
    }

    解決方案

    很簡單,我們只要把插入元素這個操作放到最后做,就可以只進行一次重解析了。


    function addAnchor(parentElement, anchorText, anchorClass) {
      
    var element = document.createElement('a');
      element.innerHTML 
    = anchorText;
      element.className 
    = anchorClass;
      parentElement.appendChild(element);
    }

    不過,要是我們想要插入很多個超鏈接到一個元素里面的話,那么這個做法還是有問題:每插入一個超鏈接還是要觸發一次重解析。下一個方案可以解決這個問題。

    方案四:通過文檔片段對象(DocumentFragment)創建一組元素

    這個方案允許我們創建并插入很多個元素而只觸發一次重解析。要實現這點需要用到所謂的文檔片段對象(DocumentFragment)。我們先在DOM之外創建一個文檔片段對象(這樣它也就不需要解析和渲染),然后我們在文檔片段對象中創建很多個元素,最后我們把這個文檔片段對象中所有的元素一次性放到DOM里面去,只觸發一次重解析。

    需求


    我們要寫一個函數,往一個指定的元素上面增加10個超鏈接。如果我們簡單的直接插入10個超鏈接到元素上面,就會觸發10次重解析。

    function addAnchors(element) {
      
    var anchor;
      
    for (var i = 0; i < 10; i ++) {
        anchor 
    = document.createElement('a');
        anchor.innerHTML 
    = 'test';
        element.appendChild(anchor);
      }
    }

    解決方案

    要解決這個問題,我們要先創建一個文檔片段對象,然后把每個新創建的超鏈接都插入到它里面去。當我們把文檔片段對象用appendChild命令插入到指定的節點時,這個文檔片段對象的所有子節點就一起被插入到指定的元素里面,而且只需要觸發一次重解析。

    function addAnchors(element) {
      
    var anchor, fragment = document.createDocumentFragment();
      
    for (var i = 0; i < 10; i ++) {
        anchor 
    = document.createElement('a');
        anchor.innerHTML 
    = 'test';
        fragment.appendChild(anchor);
      }
      element.appendChild(fragment);
    }


    注意:如無特別聲明,本文中引用的所有程序均不是Google開發,也與Google沒有其他什么關系。這些程序引發的責任均由其開發者或者所有者自己承擔,與google無關。

    emu 2010-03-01 17:20 發表評論
    ]]>
    [翻譯] 壓縮,讓網絡更快http://www.qpkxbc.shop/emu/archive/2010/02/18/313398.htmlemuemuThu, 18 Feb 2010 09:00:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/02/18/313398.htmlhttp://www.qpkxbc.shop/emu/comments/313398.htmlhttp://www.qpkxbc.shop/emu/archive/2010/02/18/313398.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/313398.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/313398.html閱讀全文

    emu 2010-02-18 17:00 發表評論
    ]]>
    谷歌的在線翻譯API很好用哈哈http://www.qpkxbc.shop/emu/archive/2010/02/15/313141.htmlemuemuMon, 15 Feb 2010 15:50:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/02/15/313141.htmlhttp://www.qpkxbc.shop/emu/comments/313141.htmlhttp://www.qpkxbc.shop/emu/archive/2010/02/15/313141.html#Feedback0http://www.qpkxbc.shop/emu/comments/commentRss/313141.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/313141.html<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      
    <head>
        
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        
    <title>Google AJAX Language API - Basic Translation</title>
        
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
        
    <script type="text/javascript">

        google.load(
    "language""1");

        
    function initialize() {
          google.language.translate(
    "Happy new year!""en""zh-CN"function(result) {
            
    if (!result.error) {
              
    var container = document.getElementById("translation");
              container.innerHTML 
    = result.translation;
            }
          });
        }
        google.setOnLoadCallback(initialize);

        
    </script>
      
    </head>
      
    <body>
        
    <div id="translation"></div>
      
    </body>
    </html>

    emu 2010-02-15 23:50 發表評論
    ]]>
    關于firefox下setTimeout的詭異函數http://www.qpkxbc.shop/emu/archive/2010/01/19/310127.htmlemuemuTue, 19 Jan 2010 11:51:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/01/19/310127.htmlhttp://www.qpkxbc.shop/emu/comments/310127.htmlhttp://www.qpkxbc.shop/emu/archive/2010/01/19/310127.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/310127.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/310127.html這個問題了,當時也沒有留心去好奇一下。今天jayyang有再提起,上mozilla查了一下,原來有文檔說明的:
    Lateness" argument

    Functions invoked by setTimeout are passed an extra "lateness" argument in Mozilla, i.e., the lateness of the timeout in milliseconds.


    寫個小腳本測試了一下,果然不錯

    var delay=3000
    if(/firefox/i.test(navigator.userAgent)){
        setTimeout(test,delay)
        alert(
    "試試等一會再確認")
    }
    else{
        alert(
    "只有 firefox 瀏覽器支持 Lateness 參數!")
    }
    function test(){
        
    var t=arguments[arguments.length-1]
        alert(
    "你點alert之前猶豫了"+(t<2?"不到"+delay:delay+t)+"毫秒")
    }


    emu 2010-01-19 19:51 發表評論
    ]]>
    flash player往頁面注入的腳本表現了adobe的臨時工水平http://www.qpkxbc.shop/emu/archive/2010/01/16/309769.htmlemuemuSat, 16 Jan 2010 05:09:00 GMThttp://www.qpkxbc.shop/emu/archive/2010/01/16/309769.htmlhttp://www.qpkxbc.shop/emu/comments/309769.htmlhttp://www.qpkxbc.shop/emu/archive/2010/01/16/309769.html#Feedback7http://www.qpkxbc.shop/emu/comments/commentRss/309769.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/309769.htmlfunction __flash__arrayToXML(obj) {
        
    var s = "<array>";
        
    for (var i=0; i<obj.length; i++) {
            s 
    += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
        }
        
    return s+"</array>";
    }
    function __flash__argumentsToXML(obj,index) {
        
    var s = "<arguments>";
        
    for (var i=index; i<obj.length; i++) {
            s 
    += __flash__toXML(obj[i]);
        }
        
    return s+"</arguments>";
    }
    function __flash__objectToXML(obj) {
        
    var s = "<object>";
        
    for (var prop in obj) {
            s 
    += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";
        }
        
    return s+"</object>";
    }
    function __flash__escapeXML(s) {
        
    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
    }
    function __flash__toXML(value) {
       var type = typeof(value);
        if (type == 
    "string") {
            return 
    "<string>" + __flash__escapeXML(value) + "</string>";
        } else if (type == 
    "undefined") {
            return 
    "<undefined/>";
        } else if (type == 
    "number") {
            return 
    "<number>" + value + "</number>";
        } else if (value == null) {
            return 
    "<null/>";
        } else if (type == 
    "boolean") {
            return value ? 
    "<true/>" : "<false/>";
        } else if (value instanceof Date) {
            return 
    "<date>" + value.getTime() + "</date>";
       } else if (value instanceof Array) {
           return __flash__arrayToXML(value);
       } else if (type == 
    "object") {
           return __flash__objectToXML(value);
       } else {
            return 
    "<null/>"; //???
        }
    }
    function __flash__addCallback(instance, name) {
      instance[name] = function () { 
        return eval(instance.CallFunction(
    "<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
      }
    }
    function __flash__removeCallback(instance, name) {
      instance[name] = null;
    }

    啥都甭說了,看看上面這幾個“+=”,已經把啥都說了。剛看到youyee同學定位到一個嚴重性能瓶頸并表情上面把這段flash往頁面里面注入的代碼貼出來的時候,emu簡直無法相信。
    還好大家都是干這行的,在flash注入完上述腳本后再覆蓋(一開始誤為重載了,感謝jee等同學的)掉這幾個函數并不為難,最多就是為之難受罷了。


    emu 2010-01-16 13:09 發表評論
    ]]>
    IE8下對cookie的限制。http://www.qpkxbc.shop/emu/archive/2009/10/29/300227.htmlemuemuThu, 29 Oct 2009 10:50:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/10/29/300227.htmlhttp://www.qpkxbc.shop/emu/comments/300227.htmlhttp://www.qpkxbc.shop/emu/archive/2009/10/29/300227.html#Feedback3http://www.qpkxbc.shop/emu/comments/commentRss/300227.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/300227.htmlemu測試了一下IE8,發現cookie的限制似乎比以前寬松多了。具體限制是:
    * 每個域名下允許50個cookie,超過了覆蓋最早寫入的cookie(或者說隊列式管理,超過了第一個出隊)
    * 同一個頁面(和從這個頁面發出的請求)子域、父域和根域各自有自己的50個cookie。
    * 單個cookie的總長度:cookieName+cookieValue+附加信息(包括等號,空格,分號,domain,expires,path之類的)不能超過5k(最多5119bytes)
    * 同一個頁面(和從這個頁面發出的請求)子域、父域和根域的全部cookie的內容長度(cookieName+cookieValue+等號,空格,分號)不能超過10k,否則全部變成httponly,無法用腳本訪問

    * 同一個頁面(和從這個頁面發出的請求)子域、父域和根域的全部cookie的內容長度(cookieName+cookieValue+等號,空格,分號)不能超過50k。

    總而言之,cookie不是用來存數據的,能不用就別用。

    邊做測試邊些博客的后果是,由于不停的清空cookie把博客的登陸態清掉了,差點文章提交失敗重新寫呵呵

    emu 2009-10-29 18:50 發表評論
    ]]>
    CSDN sd2.0大會,與csdn社區網友合影http://www.qpkxbc.shop/emu/archive/2009/10/24/299573.htmlemuemuSat, 24 Oct 2009 08:05:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/10/24/299573.htmlhttp://www.qpkxbc.shop/emu/comments/299573.htmlhttp://www.qpkxbc.shop/emu/archive/2009/10/24/299573.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/299573.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/299573.html

    emu 2009-10-24 16:05 發表評論
    ]]>
    白突發了回奇想http://www.qpkxbc.shop/emu/archive/2009/08/26/292709.htmlemuemuWed, 26 Aug 2009 11:27:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/08/26/292709.htmlhttp://www.qpkxbc.shop/emu/comments/292709.htmlhttp://www.qpkxbc.shop/emu/archive/2009/08/26/292709.html#Feedback3http://www.qpkxbc.shop/emu/comments/commentRss/292709.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/292709.html 有一天突發奇想,用表單想指定的資源發起一個post請求會如何呢?眾所周知post請求到的數據是不能cache的,那么如果這個請求指向指定的URL,該URL的cache是否也就應該跟著失效呢?
    說干就干,用 fiddler+IE/Firefox 模擬了一下整個過程,結果是令人失望的,post請求到的數據固然不會進入cache,也不會把相同URL的cache資源給沖掉。重新打開頁面的時候,還是顯示post以前cache住的那份資源。
    看來還是只好冒死用XHR去清cache了。

    emu 2009-08-26 19:27 發表評論
    ]]>
    IE8里,“about:”又回來了http://www.qpkxbc.shop/emu/archive/2009/05/22/277277.htmlemuemuFri, 22 May 2009 04:32:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/05/22/277277.htmlhttp://www.qpkxbc.shop/emu/comments/277277.htmlhttp://www.qpkxbc.shop/emu/archive/2009/05/22/277277.html#Feedback5http://www.qpkxbc.shop/emu/comments/commentRss/277277.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/277277.html
    <iframe src="about:<b style='color:red'>hello</b><script>alert(123)</script>"></iframe>

    當然還有這樣的

    showModalDialog("about:<b style='color:red'>hello</b><script>alert(123)</script>")


    在IE6.0.2600以后,大家就只好轉向更兼容的寫法了:

    <iframe src="javascript:&quot;<b style='color:red'>hello</b><script>alert(123)</script>&quot;"></iframe>

    今天偶然發現,IE8正式版下面,久違的“about:”又可以顯示和執行了呵呵。

    emu 2009-05-22 12:32 發表評論
    ]]>
    我現在在哪?http://www.qpkxbc.shop/emu/archive/2009/05/07/269353.htmlemuemuThu, 07 May 2009 02:38:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/05/07/269353.htmlhttp://www.qpkxbc.shop/emu/comments/269353.htmlhttp://www.qpkxbc.shop/emu/archive/2009/05/07/269353.html#Feedback7http://www.qpkxbc.shop/emu/comments/commentRss/269353.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/269353.html

    emu 2009-05-07 10:38 發表評論
    ]]>
    Chrome瀏覽器第一次使用google gears組建的時候會有問題http://www.qpkxbc.shop/emu/archive/2009/01/13/251099.htmlemuemuTue, 13 Jan 2009 03:46:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/01/13/251099.htmlhttp://www.qpkxbc.shop/emu/comments/251099.htmlhttp://www.qpkxbc.shop/emu/archive/2009/01/13/251099.html#Feedback3http://www.qpkxbc.shop/emu/comments/commentRss/251099.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/251099.htmlhttp://qzone.qq.com/blog/286013388-1231818216

    使用谷歌瀏覽器(chrome)的時候,有的時候腳本程序會捕獲到“Uncaught TypeError: Object #<an HTMLObjectElement> has no method 'create' ”這個錯誤,在chrome的用戶論壇上也有人在問這個問題。

    這個錯誤應該是由于最新版的谷歌瀏覽器沒有自帶完整的google gears組件導致的。看起來最新版的chrome瀏覽器會在用戶第一次使用gears組件的時候自動下載和安裝該組件,而在安裝成功以前我們雖然可以成功創建 application/x-googlegears 對象,卻無法調用它的create方法創建任何有用的東西。

    這個時候其實沒有太多的事情可以做,基本上我們我們只能檢測這個對象的create接口是否存在,發現不存在的時候提示用戶耐心等待,過一段時間后再刷新,或者下回再來看看,希望它已經自己安裝好了。



    emu 2009-01-13 11:46 發表評論
    ]]>
    打開QQ空間速度飛快的方法http://www.qpkxbc.shop/emu/archive/2009/01/11/250880.htmlemuemuSun, 11 Jan 2009 13:07:00 GMThttp://www.qpkxbc.shop/emu/archive/2009/01/11/250880.htmlhttp://www.qpkxbc.shop/emu/comments/250880.htmlhttp://www.qpkxbc.shop/emu/archive/2009/01/11/250880.html#Feedback1http://www.qpkxbc.shop/emu/comments/commentRss/250880.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/250880.html打開QQ空間速度飛快的方法

    假如你是中國電信adsl上網的用戶,在windows平臺下試用IE瀏覽器訪問QQ空間,那么
    首先呢,就是訪問http://gears.google.com/ 先把google gears裝上(最新是0.5版)。有一些同學訪問不了gears主頁或者由于某種原因安裝不上google上的最新版gears,那么可以試試到
    http://down1.tech.sina.com.cn/download/down_contents/1194710400/37265.shtml
    上下載稍微舊一點的版本(0.4版)
    網上還有更舊的版本,但是emu就沒有實驗過了。
    然后呢,你就可以訪問這個地址了:http://imgcache.qq.com/qzone/test/gears/gearsMng.html
    對于網通寬帶的朋友,就要訪問這個:http://cnc.imgcache.qq.com/qzone/test/gears/gearsMng.html
    而對于教育網的朋友,則要訪問這個:http://edu.imgcache.qq.com/qzone/test/gears/gearsMng.html
    點擊“啟用加速”,會有個gears提示,確認以后,等全部進度條走成綠色就好了,以后訪問QQ空間的時候就會自動的變得飛快。

    有幾點小技巧:
    * google gears不是很穩定,有的時候進度條走著走著就卡住不走了,這個時候可以多點幾下“啟用加速”就好了。如果還是不行,可能是網絡原因,也沒有關系,不管它就可以了,google gears會在網絡好的時候自己把沒下載完的文件給補上的。
    * 如果不大確定你的上網環境(聯通?有線寬屏?鐵通?),或者筆記本經常抱來抱去上QQ空間,那么不妨把電信、網通和教育網三個頁面都訪問一遍,分別啟用加速,這樣不管在什么環境下都可以確定獲得最好的效果。
    * 如果你用的是FireFox瀏覽器,也可以依照上面的操作。
    * 如果你用的是google的chrome瀏覽器,并且是1.0正式版以上的版本,那么它已經自帶了一個比較穩定版本的gears,跳過安裝gears這一步。但是chrome下面gears還是有時不十分穩定,雖然emu已經盡力做了兼容,在第一次使用的時候還是可能有點問題。
    * 如果用的不是windows系統,那么gears還有MacOS下的版本,支持Safari(http://gears.google.com/?platform=mac-safari)和Firefox(http://gears.google.com/?platform=mac-firefox)和linux下的版本(http://gears.google.com/?platform=linux 支持Firefox),恭喜恭喜。不過到底用起來怎么樣,emu也沒試過。
    * 如果你用的居然是opera,就認命了吧。


    emu 2009-01-11 21:07 發表評論
    ]]>
    分域名優化的時候要考慮備選IP的問題http://www.qpkxbc.shop/emu/archive/2008/05/23/202357.htmlemuemuFri, 23 May 2008 03:36:00 GMThttp://www.qpkxbc.shop/emu/archive/2008/05/23/202357.htmlhttp://www.qpkxbc.shop/emu/comments/202357.htmlhttp://www.qpkxbc.shop/emu/archive/2008/05/23/202357.html#Feedback5http://www.qpkxbc.shop/emu/comments/commentRss/202357.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/202357.html 但是在做網絡應用的時候,我們的一個域名下面有的時候會有多個ip多臺服務器,分布在不同的機房,這個時候瀏覽器會在可選的ip里面隨機的選擇一個ip。用nslookup可以看到可選的ip,用ping可以看到當前正在實用的ip。
    在多個ip的情況下,對具體的一個用戶,往往是連接到某些ip特別快,而連接到某些ip就不怎么塊。比如我現在有一個域名(和它的幾個分域名),在深圳訪問的時候有2個ip可以分,其中一個是深圳本地的服務器,一個是外地的服務器。這個時候如果頁面打開需要用到的關鍵資源依賴于這個域名,那么分域名有可能對速度不是提高而是有反作用。
    因為這種情況下,慢的資源成為了瓶頸,變成是速度的決定因素。我本來有一半的機會是快的,一半的機會是慢的,如果現在分兩個域名去下載關鍵資源,變成有1/4的機會是兩個域名都分到深圳的服務器,可以有提高,而3/4的機會是有一個以上的域名分到外地的服務器,反而變慢了,這樣提高的是少部分人的感受,而多數人的感受沒有提升或者變的更差。如果簡單的按照yahoo的優化建議分散到4個域名上,那么這個比例就變成1:15,更差了。
    因此分域名下載不能簡單的絕對化的看待,要看實際應用場景做決定。

    emu 2008-05-23 11:36 發表評論
    ]]>
    apache返回Request header field is missing ':' separatorhttp://www.qpkxbc.shop/emu/archive/2008/05/09/199542.htmlemuemuFri, 09 May 2008 08:30:00 GMThttp://www.qpkxbc.shop/emu/archive/2008/05/09/199542.htmlhttp://www.qpkxbc.shop/emu/comments/199542.htmlhttp://www.qpkxbc.shop/emu/archive/2008/05/09/199542.html#Feedback2http://www.qpkxbc.shop/emu/comments/commentRss/199542.htmlhttp://www.qpkxbc.shop/emu/services/trackbacks/199542.html Request header field is missing ':' separator
    重啟apache,關掉重開,卸掉重裝,折騰半天后還是選擇google了,原來早有人郁悶過這個問題:http://www.apachelounge.com/forum/viewtopic.php?t=602

    Just spent half of night googling.

    The main reason that I switched to 2.2.x branch is mod_proxy errors like
    "Request header field is missing ':' separator." when accessing sites localhost sites.
    Somewhere I read that it might be fixed in 2.2, so that's why I'm here.

    After 3 weeks building all neccessary modules putting and tuning all together I see the same error =/

    Problem was in Nod32's IMON module. It for some reason duplicates request. I disabled it and all works fine again.
    http://issues.apache.org/bugzilla/show_bug.cgi?id=34716

    Posting it here to help other with issues like this.


    一模一樣的現象,一模一樣的原因。把nod32的imon(也就是網絡監控)禁用了就好了。

    emu 2008-05-09 16:30 發表評論
    ]]>
    1一152期六合图库资料 四海龙王捕鱼机 幸运之门彩票网 排列三质合走势图 彩票软件七星彩 河南快3智慧彩客户端 重庆百变王牌开奖时间 足彩混合过关直播 脚手架租赁赚钱 云南快乐十分前3直 下载斗地主免费版斗地