??? 前幾天遇到一個(gè)bug,在一個(gè)填email的文本框,當(dāng)用戶錄入比較長的一段文本后(比如40位以上),頁面就死掉了。檢查后發(fā)現(xiàn)校驗(yàn)Email的是下面這樣一段javascript代碼:
? function checkEmail(email)
? {
??????? if (email.length == 0 )
??????????? return true;
???????? var validEmail = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
???????? if (validEmail.test(email))
???????? {
???????????????? return true
????????? }
?????????? return false
??? }
??? checkEmail("123456789012345678901234567890123456789012345abcdefghijkl");
?? 第一反應(yīng)是正則表達(dá)式寫的有問題,'@'前后的 ([\.-]?\w+)* 都可能會(huì)引起效率問題。下面仔細(xì)分析一下:
1. 從輸入的值來看, engine會(huì)首先匹配 \w+, 這是一個(gè)貪婪匹配,可以一直匹配到結(jié)尾;
2. 然后按優(yōu)先級(jí)開始匹配 ([\.-]?\w+)*中的 [\.-]?\w+,這個(gè)時(shí)候前面的 \w+ 為了后面的匹配成功,必須要重現(xiàn)匹配,讓出一點(diǎn)匹配的內(nèi)容,假設(shè)先讓出的是 'l',([\.-]?\w+)*匹配成功;
3. ([\.-]?\w+)* 意味著要盡量去匹配多次,再第二次對 [\.-]?\w+ 匹配,這個(gè)時(shí)候?yàn)榱说诙纹ヅ涞某晒Γ谝淮纹ヅ涞?[\.-]?\w+ 要讓出能滿足第二次 [\.-]?\w+ 的內(nèi)容,也就是它匹配到的'l',這個(gè)時(shí)候,第一次匹配的 [\.-]?\w+ 又不滿足了,\w+ 又得讓出來一個(gè)'k'。
4. 這樣未知匹配次數(shù)的 ([\.-]?\w+)* 就形成了一個(gè)很大的循環(huán),而在正則表達(dá)式中,每次匹配時(shí)被括號(hào)里模式匹配的東西都是要被存起來供以后使用的,大量的中間結(jié)果被緩存,最終導(dǎo)致IE死掉。
?? 所以這是一條典型的因?yàn)檠h(huán)嘗試匹配導(dǎo)致效率低下的正則表達(dá)式, 表達(dá)式中兩個(gè) ([\.-]?\w+)* 都可能導(dǎo)致解釋器的crash,在本例中不需要利用匹配的中間結(jié)果,所以解決的辦法很簡單,在括號(hào)加入一個(gè)冒號(hào),不保存中間結(jié)果就是了。即將那個(gè)正則表達(dá)式改成如下:
? /^\w+(?:[\.-]?\w+)*@\w+(?:[\.-]?\w+)*(\.\w{2,3})+$/
如果性能還是不能滿足需求,可以考慮把這個(gè)正則表達(dá)式拆成幾個(gè)小的表達(dá)式,分別進(jìn)行驗(yàn)證。