「前端那些事兒」① 瀏覽器渲染引擎

前言

瀏覽器基礎(chǔ)是前端知識網(wǎng)中的一個(gè)小分支溯香,也是前端開發(fā)人員必須掌握的基礎(chǔ)知識點(diǎn)。他貫穿著前端的整個(gè)網(wǎng)絡(luò)體系惠呼,項(xiàng)目優(yōu)化也是圍繞著瀏覽器進(jìn)行的滋早。

開發(fā)人員在面試的時(shí)候或許會被問到:

從你在瀏覽器輸入一個(gè)網(wǎng)址到網(wǎng)頁內(nèi)容完全被展示的這段時(shí)間內(nèi),都發(fā)生了什么事情考婴?

確實(shí)是個(gè)老生常談的問題贩虾,但問題的答案并不是唯一的,或許在三五年前沥阱,這個(gè)問題還會有一個(gè)「相對」標(biāo)準(zhǔn)的答案缎罢。

  1. 瀏覽器在接收到這個(gè)指令時(shí),會開啟一個(gè)單獨(dú)的線程來處理這個(gè)指令考杉,首先要判斷用戶輸入的是否為合法或合理的 URL 地址屁使,是否為 HTTP 協(xié)議請求,如果是那就進(jìn)入下一步
  2. 瀏覽器的瀏覽器引擎將對此 URL 進(jìn)行分析奔则,如果存在緩存「cache-control」且未過期蛮寂,則會從本地緩存提取文件(From Memory Cache,200返回碼)易茬,如果緩存「cache-control」不存在或過期酬蹋,瀏覽器將發(fā)起遠(yuǎn)程請求
  3. 通過 DNS 解析域名獲取該網(wǎng)站地址對應(yīng)的 IP 地址,連同瀏覽器的 Cookie抽莱、 userAgent 等信息向此 IP 發(fā)出 GET 請求范抓。
  4. 接下來就是經(jīng)典的「三次握手」,HTTP 協(xié)議會話食铐,瀏覽器客戶端向 Web 服務(wù)器發(fā)送報(bào)文匕垫,進(jìn)行通訊和數(shù)據(jù)傳輸。
  5. 進(jìn)入網(wǎng)站的后端服務(wù)虐呻,如 Tomcat象泵、Apache 等寞秃,還有近幾年流行的 Node.js 服務(wù)器,這些服務(wù)器上部署著應(yīng)用代碼偶惠,語言有很多春寿,如 Java、 PHP忽孽、 C++绑改、 C# 和 Javascript 等。
  6. 服務(wù)器根據(jù) URL 執(zhí)行相應(yīng)的后端應(yīng)用邏輯兄一,期間會使用到「服務(wù)器緩存」或「數(shù)據(jù)庫」厘线。
  7. 服務(wù)器處理請求并返回響應(yīng)報(bào)文,如果瀏覽器訪問過該頁面出革,緩存上有對應(yīng)資源皆的,與服務(wù)器最后修改記錄對比,一致則返回 304蹋盆,否則返回 200 和對應(yīng)的內(nèi)容费薄。
  8. 瀏覽器接收到返回信息并開始下載該 HTML文件(無緩存、200返回碼)或從本地緩存提取文件(有緩存栖雾、304返回碼)
  9. 瀏覽器的渲染引擎在拿到 HTML 文件后楞抡,便開始解析構(gòu)建 DOM 樹,并根據(jù) HTML 中的標(biāo)記請求下載指定的 MIME 類型文件(如 CSS析藕、 JavaScript 腳本等)召廷,同時(shí)使用&設(shè)置緩存等內(nèi)容。
  10. 渲染引擎根據(jù) CSS 樣式規(guī)則將 DOM 樹擴(kuò)充為渲染樹账胧,然后進(jìn)行重排竞慢、重繪。
  11. 如果含有 JS 文件將會執(zhí)行治泥,進(jìn)行 Dom 操作筹煮、緩存讀存、事件綁定等操作居夹。最終頁面將被展示在瀏覽器上败潦。

此答案精簡的概括了「后端為主的 MVC 模式」及早期 Web 應(yīng)用的瀏覽器響應(yīng)的全過程。前端技術(shù)發(fā)展到現(xiàn)在准脂,「前后端分離」「中間件直出」和「MNV*模式」也已問世劫扒,再談及此問題,答案會有所不同狸膏。

就以「前后端分離」為例沟饥,在上方答案的第4步后,緊接著就不會直接進(jìn)入后端服務(wù)器了。而會被 HTTP 和反向代理服務(wù)器贤旷,如 Ngnix广料,攔截。

  • 前置步驟1遮晚、2、3拦止、4
  • Ngnix 在監(jiān)聽到 HTTP(80端口)或 HTTPS(443端口)請求县遣,根據(jù) URL 做服務(wù)分發(fā),分發(fā)(rewrite)到后端服務(wù)器或靜態(tài)資源服務(wù)器汹族,首頁請求基本是分發(fā)到靜態(tài)服務(wù)器萧求,返回一個(gè) HTML 文件
  • 步驟7、8顶瞒、9夸政、10
  • 執(zhí)行 JS 腳本,異步 ajax榴徐、 fetch 發(fā)起 POST守问、 GET 請求,重新進(jìn)入 Ngnix 分發(fā)坑资,此次分發(fā)到后端服務(wù)器耗帕,步驟5、6袱贮、7仿便,然后返回一個(gè) xml 或 json 格式的信息,一般含有 code(返回碼)和 result(依賴信息)
  • js 回調(diào)根據(jù)返回碼執(zhí)行不同的邏輯攒巍,增刪改頁面元素嗽仪,此時(shí)可能會發(fā)生重排或重繪。首頁加載結(jié)束柒莉。

從以上步驟可以發(fā)現(xiàn)闻坚,瀏覽器可能會觸發(fā)兩次重繪,極易產(chǎn)生「白屏」或「頁面抖動」現(xiàn)象兢孝,為了解決這個(gè)問題「中間件直出」的模式應(yīng)運(yùn)而生鲤氢。另外為了擴(kuò)充大前端的陣營,吸納 IOS 和 Android西潘,Google 設(shè)計(jì)了「MNV*模式」卷玉,典型代表就是 ReactNative,但此模式已經(jīng)脫離了瀏覽器的范疇喷市,此處就不再做擴(kuò)展相种。

以上討論的渲染過程中使用到了較多的瀏覽器功能,如用戶地址欄輸入框、網(wǎng)絡(luò)請求寝并、瀏覽器文檔解析箫措、渲染引擎渲染網(wǎng)頁、 JavaScript 引擎執(zhí)行 js 腳本衬潦、客戶端存儲等斤蔓。 接下來我們介紹下瀏覽器的基本結(jié)構(gòu)組成。

瀏覽器的結(jié)構(gòu)組成

瀏覽器一般由七個(gè)模塊組成镀岛,User Interface(用戶界面)弦牡、Browser engine(瀏覽器引擎)、Rendering engine(渲染引擎)漂羊、Networking(網(wǎng)絡(luò))驾锰、JavaScript Interpreter(js解釋器)、UI Backend(UI 后端)走越、Date Persistence(數(shù)據(jù)持久化存儲) 如下圖:

瀏覽器的結(jié)構(gòu)組成
  • 用戶界面 -包括地址欄椭豫、后退/前進(jìn)按鈕、書簽?zāi)夸浀戎贾福簿褪悄闼吹降某隧撁骘@示窗口之外的其他部分
  • 瀏覽器引擎 -可以在用戶界面和渲染引擎之間傳送指令或在客戶端本地緩存中讀寫數(shù)據(jù)等赏酥,是瀏覽器中各個(gè)部分之間相互通信的核心
  • 渲染引擎 -解析DOM文檔和CSS規(guī)則并將內(nèi)容排版到瀏覽器中顯示有樣式的界面,也有人稱之為排版引擎谆构,我們常說的瀏覽器內(nèi)核主要指的就是渲染引擎
  • 網(wǎng)絡(luò) -用來完成網(wǎng)絡(luò)調(diào)用或資源下載的模塊
  • UI 后端 -用來繪制基本的瀏覽器窗口內(nèi)控件今缚,如輸入框、按鈕低淡、單選按鈕等姓言,根據(jù)瀏覽器不同繪制的視覺效果也不同,但功能都是一樣的蔗蹋。
  • JS解釋器 -用來解釋執(zhí)行JS腳本的模塊何荚,如 V8 引擎、JavaScriptCore
  • 數(shù)據(jù)存儲 -瀏覽器在硬盤中保存 cookie猪杭、localStorage等各種數(shù)據(jù)餐塘,可通過瀏覽器引擎提供的API進(jìn)行調(diào)用

作為前端開發(fā)人員,我們需要重點(diǎn)理解渲染引擎的工作原理皂吮,靈活應(yīng)用數(shù)據(jù)存儲技術(shù)戒傻,在實(shí)際項(xiàng)目開發(fā)中會經(jīng)常涉及到這兩個(gè)部分,尤其是在做項(xiàng)目性能優(yōu)化時(shí)蜂筹,理解瀏覽器渲染引擎的工作原理尤為重要需纳。而其他部分則是由瀏覽器自行管理的,開發(fā)者能控制的地方較少艺挪。今天我們就圍繞這兩個(gè)重點(diǎn)其中的一個(gè)部分「瀏覽器渲染引擎」進(jìn)行展開

瀏覽器渲染引擎

瀏覽器渲染引擎是由各大瀏覽器廠商依照 W3C 標(biāo)準(zhǔn)自行研發(fā)的不翩,也被稱之為「瀏覽器內(nèi)核」。

目前,市面上使用的主流瀏覽器內(nèi)核有5類:Trident口蝠、Gecko器钟、Presto、Webkit妙蔗、Blink傲霸。

Trident:俗稱 IE 內(nèi)核,也被叫做 MSHTML 引擎眉反,目前在使用的瀏覽器有 IE11 -昙啄,以及各種國產(chǎn)多核瀏覽器中的IE兼容模塊。另外微軟的 Edge 瀏覽器不再使用 MSHTML 引擎禁漓,而是使用類全新的引擎 EdgeHTML跟衅。

Gecko:俗稱 Firefox 內(nèi)核孵睬,Netscape6 開始采用的內(nèi)核播歼,后來的 Mozilla FireFox(火狐瀏覽器)也采用了該內(nèi)核,Gecko 的特點(diǎn)是代碼完全公開掰读,因此秘狞,其可開發(fā)程度很高,全世界的程序員都可以為其編寫代碼蹈集,增加功能烁试。因?yàn)檫@是個(gè)開源內(nèi)核,因此受到許多人的青睞拢肆,Gecko 內(nèi)核的瀏覽器也很多减响,這也是 Gecko 內(nèi)核雖然年輕但市場占有率能夠迅速提高的重要原因。

Presto:Opera 前內(nèi)核郭怪,為啥說是前內(nèi)核呢支示?因?yàn)?Opera12.17 以后便擁抱了 Google Chrome 的 Blink 內(nèi)核,此內(nèi)核就沒了寄托

Webkit:Safari 內(nèi)核鄙才,也是 Chrome 內(nèi)核原型颂鸿,主要是 Safari 瀏覽器在使用的內(nèi)核,也是特性上表現(xiàn)較好的瀏覽器內(nèi)核攒庵。也被大量使用在移動端瀏覽器上嘴纺。

Blink: 由 Google 和 Opera Software 開發(fā),在Chrome(28及往后版本)浓冒、Opera(15及往后版本)和Yandex瀏覽器中使用栽渴。Blink 其實(shí)是 Webkit 的一個(gè)分支,添加了一些優(yōu)化的新特性稳懒,例如跨進(jìn)程的 iframe熔萧,將 DOM 移入 JavaScript 中來提高 JavaScript 對 DOM 的訪問速度等,目前較多的移動端應(yīng)用內(nèi)嵌的瀏覽器內(nèi)核也漸漸開始采用 Blink。

渲染引擎的工作流程

瀏覽器渲染引擎最重要的工作就是將 HTML 和 CSS 文檔解析組合最終渲染到瀏覽器窗口上佛致。如下圖所示贮缕,渲染引擎在接受到 HTML 文件后主要進(jìn)行了以下操作:解析 HTML 構(gòu)建 DOM 樹 -> 構(gòu)建渲染樹 -> 渲染樹布局 -> 渲染樹繪制。

渲染引擎工作流程

解析 HTML 構(gòu)建 DOM 樹時(shí)渲染引擎會將 HTML 文件的便簽元素解析成多個(gè) DOM 元素對象節(jié)點(diǎn)俺榆,并且將這些節(jié)點(diǎn)根據(jù)父子關(guān)系組成一個(gè)樹結(jié)構(gòu)感昼。同時(shí) CSS 文件被解析成 CSS 規(guī)則表,然后將每條 CSS 規(guī)則按照「從右向左」的方式在 DOM 樹上進(jìn)行逆向匹配罐脊,生成一個(gè)具有樣式規(guī)則描述的 DOM 渲染樹定嗓。接下來就是將渲染樹進(jìn)行布局、繪制的過程萍桌。首先根據(jù) DOM 渲染樹上的樣式規(guī)則宵溅,對 DOM 元素進(jìn)行大小和位置的定位,關(guān)鍵屬性如position;width;margin;padding;top;border;...上炎,接下來再根據(jù)元素樣式規(guī)則中的color;background;shadow;...規(guī)則進(jìn)行繪制恃逻。

另外,這個(gè)過程是逐步完成的藕施,為了更好的用戶體驗(yàn)寇损,渲染引擎將會盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會等到所有的 html 都解析完成之后再去構(gòu)建和布局 render 樹裳食。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容矛市,同時(shí),可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容诲祸。

再者浊吏,需要注意的是,在瀏覽器渲染完首屏頁面后救氯,如果對 DOM 進(jìn)行操作會引起瀏覽器引擎對 DOM 渲染樹的重新布局和重新繪制找田,我們叫做「重排」和「重繪」,由于重排和重繪是前后依賴的關(guān)系径密,重繪發(fā)生時(shí)未必會觸發(fā)渲染引擎的重排午阵,但是如果發(fā)生了重排就必然會觸發(fā)重繪操作,這樣帶來的性能損害就是巨大的享扔。因此我們在做性能優(yōu)化的時(shí)候應(yīng)該遵循「避免重排底桂;減少重繪」的原則。

不同瀏覽器內(nèi)核間的差異

在不同的瀏覽器內(nèi)核下惧眠, 瀏覽器頁面渲染的流程略有不同

webkit 內(nèi)核工作流程
Geoko 內(nèi)核工作流程

上面兩幅圖分別是 Webkit 和 Geoko 內(nèi)核渲染 DOM 的工作流程籽懦,對比可以看出,兩者的區(qū)別主要在于 CSS 樣式表的解析時(shí)機(jī)氛魁,Webkit 內(nèi)核下暮顺,HTML 和 CSS 文件的解析是同步的厅篓,而 Geoko 內(nèi)核下,CSS 文件需要等到 HTML 文件解析成內(nèi)容 Sink 后才進(jìn)行解析捶码。

另外描述術(shù)語也有不同羽氮,除此之外兩者的流程就基本相同了,其中最重要的三個(gè)部分就是 「HTML 的解析」「CSS 的解析」「渲染樹的生成」惫恼。這三個(gè)部分的原理比較深档押,會涉及到「詞法分析」「語法分析」「轉(zhuǎn)換」「解釋」等數(shù)據(jù)結(jié)構(gòu)的知識,比較枯燥祈纯,一般我們了解到這里就夠了令宿,想深入了解的同學(xué)可以閱讀此篇譯文,瀏覽器的工作原理腕窥,里面詳細(xì)的解釋了以上三個(gè)部分的流程和原理粒没。此處就不再多做贅述了。

關(guān)于 CSS 規(guī)則的匹配

上面我們提到過簇爆, CSS 規(guī)則是按照「從右向左」的方式在 DOM 樹上進(jìn)行逆向匹配的癞松,最終生成一個(gè)具有樣式規(guī)則描述的 DOM 渲染樹。

但是你知道為什么要「從右向左」做逆向匹配嗎冕碟?

我們重新回看【webkit 內(nèi)核工作流程圖】

webkit 內(nèi)核工作流程

CSS 規(guī)則匹配是發(fā)生在webkit引擎的「Attachment」過程中拦惋,瀏覽器要為每個(gè) DOM Tree 中的元素?cái)U(kuò)充 CSS 樣式規(guī)則(匹配 Style Rules)匆浙。對于每個(gè) DOM 元素安寺,必須在所有 Style Rules 中找到符合的 selector 并將對應(yīng)的規(guī)則進(jìn)行合并。選擇器的「解析」實(shí)際是在這里執(zhí)行的首尼,在遍歷 DOM Tree 時(shí)挑庶,從 Style Rules 中去尋找對應(yīng)的 selector。

我們來舉一個(gè)最簡單的栗子:

<template>
<div>
  <div class="t">
    <span>test</span>
    <p>test</p>
  <div>
</div>
</template>

<style>
div{ color: #000; }
div .t span{ color: red; }
div .t p{color: blue; }
</style>

此處我們有一個(gè) html 元素 和一個(gè) style 元素软能,兩者需要做遍歷匹配

此處會有 4*3 個(gè)匹配項(xiàng)迎捺,如果做正向匹配,在遇到 <span> 標(biāo)簽匹配 div .t p{ color: red; } 到匹配項(xiàng)時(shí)查排,計(jì)算機(jī)首先要找到<span> 標(biāo)簽的父標(biāo)簽和祖父標(biāo)簽凳枝,判斷他們是否滿足div .t的規(guī)則,然后再匹配<span>是否為p標(biāo)簽跋核,此處匹配不成功岖瑰,產(chǎn)生了三次浪費(fèi)。

如果時(shí)逆向匹配砂代,那么第一次對比<span>是否為p標(biāo)簽便可排除此規(guī)則蹋订,效率更高。

如果將 HTML 結(jié)構(gòu)變復(fù)雜刻伊,CSS 規(guī)則表變龐大露戒,那么椒功,「逆向匹配」的優(yōu)勢就遠(yuǎn)大于「正向匹配」了,因?yàn)槠ヅ涞那闆r遠(yuǎn)遠(yuǎn)低于不匹配的情況智什。另外动漾,如果在選擇器結(jié)尾加上通配符「*」,那么「逆向匹配」的優(yōu)勢就大打折扣了荠锭,這也就是很多優(yōu)化原則提到的「盡量避免在選擇器末尾添加通配符」的原因谦炬。

極限了想,如果我們的樣式表不存在嵌套關(guān)系节沦,如下:

<template>
  <div class="t">
    <span class="div_t_span">test</span>
    <p class="div_t_p">test</p>
  <div>
</template>

<style>
div{ color: #000; }
.div_t_span{ color: red; }
.div_t_p{color: blue; }
</style

那么引擎的「Attachment」過程將得到極大的精簡键思,效率也是可想而知的,這就是為什么「微信小程序」樣式表不建議使用關(guān)系行寫法的原因甫贯。

相關(guān)的性能優(yōu)化

我們大致可以在以上案例中看到同瀏覽器渲染引擎相關(guān)的可行優(yōu)化點(diǎn)吼鳞。

大致為以下幾種

減少 JS 加載對 Dom 渲染的影響

將 JS 文件放在 HTML 文檔后加載,或者使用異步的方式加載 JS 代碼

避免重排叫搁,減少重繪

在做 css 動畫的時(shí)候減少使用 width赔桌、 margin、 padding 等影響 CSS 布局對規(guī)則渴逻,可以使用 CSS3 的 transform 代替疾党。另外值得注意的是,在加載大量的圖片元素時(shí)惨奕,盡量預(yù)先限定圖片的尺寸大小雪位,否則在圖片加載過程中會更新圖片的排版信息,產(chǎn)生大量的重排梨撞。

減少使用關(guān)系型樣式表的寫法

直接使用唯一的類名即可最大限度的提升渲染效率雹洗,另外盡量避免在選擇器末尾添加通配符

減少 DOM 的層級

減少無意義的 dom 層級可以減少 渲染引擎 Attachment 過程中的匹配計(jì)算量

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卧波,隨后出現(xiàn)的幾起案子时肿,更是在濱河造成了極大的恐慌,老刑警劉巖港粱,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件螃成,死亡現(xiàn)場離奇詭異,居然都是意外死亡查坪,警方通過查閱死者的電腦和手機(jī)寸宏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咪惠,“玉大人击吱,你說我怎么就攤上這事∫C粒” “怎么了覆醇?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵朵纷,是天一觀的道長。 經(jīng)常有香客問我永脓,道長袍辞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任常摧,我火速辦了婚禮搅吁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘落午。我一直安慰自己谎懦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布溃斋。 她就那樣靜靜地躺著界拦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梗劫。 梳的紋絲不亂的頭發(fā)上享甸,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音梳侨,去河邊找鬼蛉威。 笑死,一個(gè)胖子當(dāng)著我的面吹牛走哺,可吹牛的內(nèi)容都是我干的蚯嫌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼割坠,長吁一口氣:“原來是場噩夢啊……” “哼齐帚!你這毒婦竟也來了妒牙?” 一聲冷哼從身側(cè)響起彼哼,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎湘今,沒想到半個(gè)月后敢朱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摩瞎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年拴签,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旗们。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚓哩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出上渴,到底是詐尸還是另有隱情岸梨,我是刑警寧澤喜颁,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站曹阔,受9級特大地震影響半开,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赃份,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一寂拆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抓韩,春花似錦纠永、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彪薛,卻和暖如春茂装,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背善延。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工少态, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人易遣。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓彼妻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豆茫。 傳聞我的和親對象是個(gè)殘疾皇子侨歉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容