JavaScript性能優(yōu)化

內(nèi)存管理

內(nèi)存管理流程
  • 申請(qǐng)內(nèi)存空間
  • 使用內(nèi)存空間
  • 釋放內(nèi)存空間

垃圾回收與常見(jiàn)GC算法

js中的垃圾
  • js中的內(nèi)存管理是自動(dòng)的栏饮;
  • 對(duì)象不再被引用時(shí)是垃圾;
  • 對(duì)象不能從根上訪問(wèn)到時(shí)是垃圾。
js中的可達(dá)對(duì)象
  • 可以訪問(wèn)到的對(duì)象就是可達(dá)對(duì)象(引用优炬、作用域鏈)颁井;
  • 可達(dá)的標(biāo)準(zhǔn)就是從根出發(fā)是否能夠被找到;
  • js中的根可以理解為全局變量對(duì)象蠢护。

當(dāng)變量對(duì)象不可達(dá)時(shí)雅宾,就會(huì)被視作垃圾,js引擎會(huì)自動(dòng)找到它并進(jìn)行垃圾回收糊余。

GC算法介紹

GC是垃圾回收機(jī)制的簡(jiǎn)寫(xiě)秀又,GC可以找到內(nèi)存中的垃圾、并釋放和回收空間贬芥。
算法是工作時(shí)查找和回收時(shí)所遵循的原則吐辙。

  • GC中的垃圾是什么
    • 程序中不再需要使用的對(duì)象;
    • 程序中不能再訪問(wèn)到的對(duì)象蘸劈。
常見(jiàn)的GC算法
  • 引用計(jì)數(shù)
    通過(guò)引用計(jì)數(shù)器對(duì)對(duì)象進(jìn)行引用計(jì)數(shù)昏苏,引用關(guān)系改變時(shí)修改引用數(shù)字,當(dāng)引用數(shù)字為0時(shí)立即進(jìn)行回收威沫。
    優(yōu)點(diǎn)
    1.發(fā)現(xiàn)垃圾時(shí)立即回收贤惯;
    2.最大限度減少程序暫停,減少程序卡頓時(shí)間棒掠。
    缺點(diǎn)
    1.無(wú)法回收循環(huán)引用的對(duì)象孵构;
    2.時(shí)間開(kāi)銷(xiāo)大、資源消耗較大烟很。

  • 標(biāo)記清除
    分為標(biāo)記階段和清除階段:首先遍歷所有對(duì)象標(biāo)記活動(dòng)對(duì)象(可達(dá)對(duì)象)颈墅,然后再次遍歷清除沒(méi)有標(biāo)記對(duì)象,回收相應(yīng)的空間雾袱,結(jié)束后還會(huì)清除所有標(biāo)記方便下次進(jìn)行GC恤筛。
    優(yōu)點(diǎn)
    相對(duì)于引用計(jì)數(shù)算法,可以回收循環(huán)引用的對(duì)象芹橡。
    缺點(diǎn)
    1.空間碎片化:當(dāng)前所回收的對(duì)象在地址上不連續(xù)毒坛,不能最大化地使用空間;
    2.不會(huì)立即回收垃圾對(duì)象林说。

  • 標(biāo)記整理
    可以看作是標(biāo)記清除的增強(qiáng)煎殷,標(biāo)記階段與標(biāo)記清除算法一致,清楚階段會(huì)先執(zhí)行整理腿箩,移動(dòng)對(duì)象的位置豪直。
    優(yōu)點(diǎn)
    減少碎片化空間。
    缺點(diǎn)
    不會(huì)立即回收垃圾對(duì)象度秘。

  • 分代回收
    將內(nèi)存分為新生代、老生代,針對(duì)不同對(duì)象采用不同的算法剑梳。詳見(jiàn)V8的垃圾回收策略唆貌。

V8引擎的垃圾回收

V8是一款主流的js執(zhí)行引擎,采用即時(shí)編譯垢乙,內(nèi)存設(shè)限(1.對(duì)于瀏覽器來(lái)說(shuō)足夠使用锨咙;2.如果上限再大那么垃圾回收時(shí)間會(huì)超過(guò)用戶感知)。

V8的垃圾回收策略

采用分代回收的思想追逮。

V8中的常用GC算法
  • 分代回收
  • 空間復(fù)制
  • 標(biāo)記清除
  • 標(biāo)記整理
  • 增量標(biāo)記

增量標(biāo)記
將原本需要一次性遍歷堆內(nèi)存的操作改為增量標(biāo)記的方式酪刀,先標(biāo)記內(nèi)存中的一部分對(duì)象然后暫停,將執(zhí)行權(quán)重新交給JS主線程钮孵,待主線程任務(wù)執(zhí)行完畢后再?gòu)脑瓉?lái)暫停標(biāo)記的地方繼續(xù)標(biāo)記骂倘,直到標(biāo)記完整個(gè)堆內(nèi)存。

V8如何回收新生代對(duì)象

新生代對(duì)象指的是存活時(shí)間較的對(duì)象巴席。V8的內(nèi)存空間一分為二历涝,小空間用于存儲(chǔ)新生代對(duì)象(32M|16M)。

回收過(guò)程采用的是復(fù)制算法+標(biāo)記整理:
新生代內(nèi)存區(qū)被等分為兩個(gè)空間漾唉,使用空間為From存儲(chǔ)活動(dòng)對(duì)象荧库,空閑空間為T(mén)o。開(kāi)始進(jìn)行GC赵刑,會(huì)檢查From區(qū)中的活動(dòng)對(duì)象分衫,標(biāo)記整理后將活動(dòng)對(duì)象拷貝至To,清空(釋放)From區(qū)般此,最后將From和To互換蚪战。

細(xì)節(jié)說(shuō)明:
拷貝過(guò)程中可能出現(xiàn)晉升(將新生代對(duì)象移動(dòng)至老生代),情況為:
1.一輪GC后還存活的新生代需要晉升恤煞;
2.To空間的使用率超過(guò)25%屎勘。

V8如何回收老生代對(duì)象

老生代對(duì)象指的是存活時(shí)間較長(zhǎng)的對(duì)象。老生代對(duì)象存儲(chǔ)至右側(cè)的老生代區(qū)域(1.4G|700M)居扒。

回收過(guò)程主要采用標(biāo)記清除概漱、標(biāo)記整理和增量標(biāo)記:
首先使用標(biāo)記清除完成垃圾空間的回收,當(dāng)存在新生代對(duì)象晉升到老生代區(qū)域而由于空間碎片化導(dǎo)致空間不足時(shí)則需要采用標(biāo)記整理進(jìn)行空間優(yōu)化喜喂,采用增量標(biāo)記進(jìn)行效率優(yōu)化瓤摧。

新老生代對(duì)象垃圾回收對(duì)比
  1. 新生代區(qū)域垃圾回收使用空間換時(shí)間。在新生代內(nèi)存中玉吁,大部分對(duì)象的生命周期較短照弥,因此時(shí)間效率可觀;
  2. 老生代區(qū)域垃圾回收不適合復(fù)制算法进副。老生代內(nèi)存中可能會(huì)存儲(chǔ)大量對(duì)象这揣,如果再將空間一分為二為造成空間的大量浪費(fèi)悔常。
V8引擎執(zhí)行流程

預(yù)解析的優(yōu)點(diǎn)

  • 跳過(guò)未被使用的代碼;
  • 不生成AST给赞,創(chuàng)建無(wú)變量引用和聲明的scopes机打;
  • 依據(jù)規(guī)范拋出特定錯(cuò)誤;
  • 解析速度更快片迅。

全量解析

  • 解析被使用的代碼残邀;
  • 生成AST;
  • 構(gòu)建具體scopes信息柑蛇,變量引用芥挣、聲明等;
  • 拋出所有語(yǔ)法錯(cuò)誤耻台。

Performance工具

使用目的

Performance提供多種監(jiān)控方式空免,讓開(kāi)發(fā)者可以時(shí)刻關(guān)注當(dāng)前內(nèi)存的變化以確定當(dāng)前內(nèi)存空間的使用是否合理。

使用步驟
  1. 打開(kāi)瀏覽器輸入目標(biāo)網(wǎng)址粘我;
  2. 進(jìn)入開(kāi)發(fā)人員工具面板鼓蜒,選擇性能;
  3. 開(kāi)啟錄制功能征字,訪問(wèn)具體界面都弹;
  4. 執(zhí)行用戶行為,一段時(shí)間后停止錄制匙姜;
  5. 分析界面中記錄的內(nèi)存信息畅厢。
內(nèi)存問(wèn)題的體現(xiàn)
  • 頁(yè)面出現(xiàn)延遲加載或經(jīng)常性暫停-存在頻繁的垃圾回收
  • 頁(yè)面持續(xù)性出現(xiàn)糟糕的性能-內(nèi)存膨脹氮昧;
  • 頁(yè)面的性能隨時(shí)間延長(zhǎng)越來(lái)越差-內(nèi)存泄漏框杜。
監(jiān)控內(nèi)存的幾種方式

界定內(nèi)存問(wèn)題的標(biāo)準(zhǔn):

  • 內(nèi)存泄漏:內(nèi)存使用持續(xù)升高;
  • 內(nèi)存膨脹:在多數(shù)設(shè)備上都存在性能問(wèn)題袖肥;
  • 頻繁垃圾回收:通過(guò)內(nèi)存變化圖進(jìn)行分析咪辱。

方式:

  • 瀏覽器任務(wù)管理器;
  • Timeline時(shí)序圖記錄椎组;
  • 堆快照查找分離DOM油狂;
  • 判斷是否存在頻繁的垃圾回收。
堆快照查找分離DOM

DOM存在的幾種狀態(tài)

  • 界面元素存活在DOM樹(shù)上寸癌;
  • 垃圾對(duì)象的DOM節(jié)點(diǎn)——DOM從DOM樹(shù)上脫離专筷,js里沒(méi)有引用;
  • 分離狀態(tài)的DOM節(jié)點(diǎn)——DOM從DOM樹(shù)上脫離蒸苇,js里有引用磷蛹,界面上看不見(jiàn)但是占用內(nèi)存浪費(fèi)空間。
判斷是否存在頻繁GC

為什么需要確定存在頻繁GC溪烤?

  • GC工作時(shí)應(yīng)用程序是停止的味咳;
  • 頻繁且過(guò)長(zhǎng)的GC會(huì)導(dǎo)致應(yīng)用假死庇勃;
  • 用戶使用中感知應(yīng)用卡頓。

確定方式

  • Timeline中頻繁的上升下降槽驶;
  • 任務(wù)管理器中數(shù)據(jù)頻繁的增加減小匪凉。

代碼優(yōu)化實(shí)例

堆棧處理
  • JS執(zhí)行環(huán)境;
  • 執(zhí)行環(huán)境棧(ECStack, execution context stack)捺檬;
  • 執(zhí)行上下文;
  • VO(G)贸铜,全局變量對(duì)象堡纬。
  1. 基本數(shù)據(jù)類型是按值進(jìn)行操作;
  2. 基本數(shù)據(jù)類型的值存放在棧區(qū)蒿秦;
  3. 無(wú)論是棧內(nèi)存還是后續(xù)引用數(shù)據(jù)類型會(huì)使用的堆內(nèi)存都屬于計(jì)算機(jī)內(nèi)存烤镐;
  4. GO(全局對(duì)象)。
引用類型堆棧處理
函數(shù)堆棧處理
  1. 創(chuàng)建函數(shù)和創(chuàng)建變量類似棍鳖,函數(shù)名此時(shí)就可以看作是一個(gè)變量名炮叶,存放在VO中;
  2. 單獨(dú)開(kāi)辟一個(gè)堆內(nèi)存用于存放函數(shù)體(字符串形式代碼)渡处,當(dāng)前內(nèi)存地址也會(huì)有一個(gè)16進(jìn)制數(shù)值地址镜悉;
  3. 創(chuàng)建函數(shù)的時(shí)候,它的作用域[[scope]]就已經(jīng)確定了(創(chuàng)建函數(shù)時(shí)所在的執(zhí)行上下文)医瘫;
  4. 創(chuàng)建函數(shù)之后會(huì)將它的內(nèi)存地址存放在棧區(qū)與對(duì)應(yīng)的函數(shù)名進(jìn)行關(guān)聯(lián)侣肄。

函數(shù)執(zhí)行,目的就是為了將函數(shù)對(duì)應(yīng)的堆內(nèi)存里的字符串形式代碼進(jìn)行執(zhí)行醇份。代碼在執(zhí)行的時(shí)候肯定需要有一個(gè)環(huán)境稼锅,此時(shí)就意味著函數(shù)在執(zhí)行的時(shí)候會(huì)生成一個(gè)新的執(zhí)行上下文來(lái)管理函數(shù)體中的代碼。

函數(shù)執(zhí)行時(shí)做的事情:

  1. 確定作用域鏈:<當(dāng)前執(zhí)行上下文僚纷、上級(jí)執(zhí)行上下文>矩距;
  2. 確定this指向;
  3. 初始化arguments對(duì)象怖竭;
  4. 形參賦值:它相當(dāng)于是變量聲明锥债,然后將聲明的變量放置于AO;
  5. 變量提升侵状;
  6. 執(zhí)行代碼赞弥。
閉包堆棧處理

函數(shù)執(zhí)行時(shí)創(chuàng)建的私有執(zhí)行上下文當(dāng)中引用的一個(gè)堆被外部的執(zhí)行上下文中的變量所引用,因此當(dāng)函數(shù)執(zhí)行完后趣兄,該私有執(zhí)行上下文就不能被釋放绽左。

  1. 閉包是一種機(jī)制,通過(guò)私有上下文來(lái)保護(hù)當(dāng)中變量的機(jī)制艇潭;
  2. 也可以認(rèn)為當(dāng)創(chuàng)建的某一個(gè)執(zhí)行上下文不被釋放的時(shí)候形成了閉包拼窥;
  3. 保護(hù)戏蔑、保存數(shù)據(jù)。
閉包與垃圾回收
  1. 瀏覽器都自有垃圾回收機(jī)制(內(nèi)存管理鲁纠,V8為例)总棵;
  2. 棧空間改含、堆空間情龄;
  3. 堆:當(dāng)前堆內(nèi)存如果被占用,就能被釋放掉捍壤,但是如果確認(rèn)后續(xù)不再使用這個(gè)內(nèi)存中的數(shù)據(jù)骤视,可以自己主動(dòng)置空,然后瀏覽器就會(huì)對(duì)其進(jìn)行回收鹃觉;
  4. 棧:當(dāng)前上下文中是否有內(nèi)容专酗,被其他上下文的變量所占用,如果有則無(wú)法釋放(閉包)盗扇。
循環(huán)添加事件實(shí)現(xiàn)
  • 閉包
  • 自定義屬性
  • 事件委托
變量局部化

可以提交代碼的執(zhí)行效率(減少了數(shù)據(jù)訪問(wèn)時(shí)需要查找的路徑)祷肯。

緩存數(shù)據(jù)

對(duì)于需要多次使用的數(shù)據(jù)進(jìn)行提前保存,后續(xù)進(jìn)行使用疗隶。

  1. 減少聲明和語(yǔ)句數(shù)(詞法 語(yǔ)法)佑笋;
  2. 緩存數(shù)據(jù)(作用域鏈查找變快)。
減少訪問(wèn)層級(jí)
防抖與節(jié)流

在一些高頻率事件觸發(fā)的場(chǎng)景下我們不希望對(duì)應(yīng)的事件處理函數(shù)多次執(zhí)行斑鼻。
常見(jiàn)的應(yīng)用場(chǎng)景

  • 滾動(dòng)事件
  • 輸入的模糊匹配
  • 輪播圖切換
  • 點(diǎn)擊操作
  • ...
    瀏覽器默認(rèn)情況下都會(huì)有自己的監(jiān)聽(tīng)事件間隔(4-6ms)允青,如果檢測(cè)到多次事件的監(jiān)聽(tīng)執(zhí)行,那么就會(huì)造成不必要的資源浪費(fèi)卵沉。

前置場(chǎng)景:界面上有一個(gè)按鈕可以多次點(diǎn)擊颠锉。
防抖:對(duì)于這個(gè)高頻的操作來(lái)說(shuō),我們只希望識(shí)別一次點(diǎn)擊史汗,可以認(rèn)為是第一次或者最后一次琼掠;
節(jié)流:對(duì)于高頻操作,我們可以自己來(lái)設(shè)置頻率停撞,讓本來(lái)會(huì)執(zhí)行很多次的事件觸發(fā)瓷蛙,按照我們定義的頻率減少觸發(fā)的次數(shù)。

防抖函數(shù)實(shí)現(xiàn)

// 防抖函數(shù)實(shí)現(xiàn)
/**
* handle 最終需要執(zhí)行的事件監(jiān)聽(tīng)
* wait 事件觸發(fā)多久后開(kāi)始執(zhí)行
* immidiate 控制執(zhí)行第一次還是最后一次戈毒,false執(zhí)行最后一次
*/
function myDebounce(handle, wait, immidiate) {
    // 參數(shù)類型判斷及默認(rèn)值處理
    if(typeof handle !== function) throw new Error('handle must be a function')
    if(typeof wait === 'undefined') wait = 300
    if(typeof wait === 'boolean') {
        immidiate = wait
        wait = 300
    }
    if(typeof immidiate !== 'boolean') immidiate = false

    // 所謂的防抖效果就是有一個(gè)“人”管理handle的執(zhí)行次數(shù)
    // 如果我們想要執(zhí)行最后一次艰猬,那就意味著無(wú)論我們點(diǎn)擊了多少次,前面的N-1次都無(wú)用
    let timer = null
    return function proxy() {
        clearTimeout(timer)
        timer = setTimeout(()=>{
            handle()
        }, wait)
    }
}

節(jié)流函數(shù)實(shí)現(xiàn)
在自定義的一段時(shí)間內(nèi)讓事件觸發(fā)

// 節(jié)流函數(shù)實(shí)現(xiàn)
function myThottle(handle, wait) {
    // 參數(shù)類型判斷及默認(rèn)值處理
    if(typeof handle !== function) throw new Error('handle must be a function')
    if(typeof wait === 'undefined') wait = 500

    let previous = 0
    let timer = null

    return function proxy(...args) {
        let now = new Date()  // 定義變量記錄當(dāng)前執(zhí)行的時(shí)間點(diǎn)
        let self = this
        let interval = wait - (now - previous)

        // 非高頻次操作埋市,執(zhí)行
        if(interval <= 0) {
            // 處理臨界情況
            clearTimeout(timer)
            timer = null
            handle.call(self, ...args)
            previous = new Date()
        } else if(!timer) {
            // 當(dāng)系統(tǒng)中沒(méi)有定時(shí)器冠桃,自定義一個(gè)定時(shí)器讓handle在interval之后執(zhí)行
            timer = setTimeout(() => {
                clearTimeout(timer)  // 清除系統(tǒng)中的定時(shí)器,但是timer中的值還在
                timer = null
                handle.call(self, ...args)
                previous = new Date()
            }, interval);
        }


    }
}
減少判斷層級(jí)

如果出現(xiàn)if多層嵌套的情況道宅,考慮將其改為使用提前return的操作食听。

減少循環(huán)體活動(dòng)

減少對(duì)象成員及數(shù)組項(xiàng)的查找次數(shù)胸蛛。每次循環(huán)都要查找item.length,這樣做很耗時(shí)樱报,由于該值在循環(huán)運(yùn)行過(guò)程中從未變過(guò)葬项,因此產(chǎn)生了不必要的性能損失,提高整個(gè)循環(huán)的性能很簡(jiǎn)單迹蛤,只查找一次屬性民珍,并把值存儲(chǔ)到一個(gè)局部變量中,然后在控制條件中使用整個(gè)變量盗飒。

字面量與構(gòu)造式

盡量用對(duì)象字面量的方式來(lái)創(chuàng)建對(duì)象穷缤。
字面量的優(yōu)勢(shì):

  1. 它的代碼量更少,更易讀箩兽;
  2. 對(duì)象字面量運(yùn)行速度更快,因?yàn)樗鼈兛梢栽诮馕龅臅r(shí)候被優(yōu)化章喉。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汗贫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秸脱,更是在濱河造成了極大的恐慌落包,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊唇,死亡現(xiàn)場(chǎng)離奇詭異咐蝇,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)巷查,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)有序,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人岛请,你說(shuō)我怎么就攤上這事旭寿。” “怎么了崇败?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵盅称,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我后室,道長(zhǎng)缩膝,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任岸霹,我火速辦了婚禮疾层,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贡避。我一直安慰自己云芦,他們只是感情好俯逾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舅逸,像睡著了一般桌肴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琉历,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天坠七,我揣著相機(jī)與錄音,去河邊找鬼旗笔。 笑死彪置,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蝇恶。 我是一名探鬼主播拳魁,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼撮弧!你這毒婦竟也來(lái)了潘懊?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贿衍,失蹤者是張志新(化名)和其女友劉穎授舟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贸辈,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡释树,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了擎淤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奢啥。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嘴拢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炊汤,我是刑警寧澤正驻,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站抢腐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏卦洽。R本人自食惡果不足惜酗失,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一拖刃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧硬耍,春花似錦坯认、人聲如沸牛哺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颁督。三九已至,卻和暖如春试疙,著一層夾襖步出監(jiān)牢的瞬間怀跛,已是汗流浹背骇两。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拂铡,地道東北人壹无。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像感帅,于是被迫代替她去往敵國(guó)和親斗锭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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