No4.瀏覽器中的頁(yè)面循環(huán)系統(tǒng)

前段時(shí)間在《極客時(shí)間》上學(xué)了一個(gè)專欄眷柔,通篇略過(guò)期虾,干貨不少原朝,但理解相當(dāng)不夠透徹,于是計(jì)劃用幾周的時(shí)間镶苞,對(duì)本專欄內(nèi)容用作者的總結(jié)以及自己的相對(duì)逐字理解喳坠,來(lái)個(gè)通篇的文字記錄學(xué)習(xí),書讀百遍宾尚,其義自現(xiàn)丙笋。
本篇是這個(gè)專欄的第四章:《瀏覽器中的頁(yè)面循環(huán)系統(tǒng)》。本章分為六節(jié)煌贴。

15|消息隊(duì)列和事件循環(huán):頁(yè)面是怎么“活”起來(lái)的御板?


本節(jié)主要專門介紹頁(yè)面的事件循環(huán)系統(tǒng),希望通過(guò)幾段總結(jié)能對(duì)頁(yè)面的事件循環(huán)系統(tǒng)有一個(gè)整體上的理解牛郑。

使用單線程處理安排好的任務(wù)

單線程處理的流程就是把所有任務(wù)代碼按照順序?qū)戇M(jìn)主線程里怠肋,等線程運(yùn)行時(shí),這些任務(wù)按照順序在線程中執(zhí)行淹朋,等所有任務(wù)執(zhí)行完成笙各,線程自動(dòng)退出。

在線程運(yùn)行過(guò)程中處理任務(wù)

當(dāng)然并非所有任務(wù)都可以使用單線程處理础芍,有時(shí)我們需要在線程運(yùn)行的過(guò)程中處理任務(wù)杈抢。
那么要想在線程運(yùn)行過(guò)程中,能接受并執(zhí)行新的任務(wù)仑性,就需要采用事件循環(huán)機(jī)制惶楼。
相較與單線程處理任務(wù),此線程做了兩點(diǎn)改進(jìn):

  • 引入了循環(huán)機(jī)制诊杆。(比如一個(gè)實(shí)現(xiàn)方式是添加for循環(huán)歼捐。線程一直循環(huán)執(zhí)行)。
  • 引入了事件晨汹。
處理其他線程發(fā)送過(guò)來(lái)的任務(wù)

如何設(shè)計(jì)好一個(gè)線程模型豹储,能讓其能夠接受其他線程發(fā)送的消息呢?
一個(gè)通用的模式是消息隊(duì)列:「消息隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu)淘这、可以存放要執(zhí)行的任務(wù)剥扣。它符合隊(duì)列“先進(jìn)先出”的特點(diǎn)÷燎睿」
有了隊(duì)列之后繼續(xù)改進(jìn)步驟如下:

  • 添加一個(gè)消息隊(duì)列朦乏。
  • IO線程中產(chǎn)生的新任務(wù)添加進(jìn)消息隊(duì)列尾部。
  • 渲染主進(jìn)程會(huì)循環(huán)地從消息隊(duì)列頭部中讀取任務(wù)氧骤,執(zhí)行任務(wù)。
處理其他進(jìn)程發(fā)送過(guò)來(lái)的任務(wù)

渲染進(jìn)程專門有一個(gè) IO 線程用來(lái)接收其他進(jìn)程傳進(jìn)來(lái)的消息吃引,接收到消息之后筹陵,會(huì)將這些消息組裝成任務(wù)發(fā)送給渲染主線程刽锤,后續(xù)的步驟就和前面的“處理其他線程發(fā)送的任務(wù)”一樣。

消息隊(duì)列中的任務(wù)類型

消息隊(duì)列中的任務(wù)都有哪些呢朦佩?
輸入事件(鼠標(biāo)滾動(dòng)并思、點(diǎn)擊、移動(dòng))语稠、微任務(wù)宋彼、文件讀寫、WebSocket仙畦、JavaScript 定時(shí)器等等输涕。除此之外,消息隊(duì)列中還包含了很多與頁(yè)面相關(guān)的事件慨畸,如 JavaScript 執(zhí)行莱坎、解析 DOM、樣式計(jì)算寸士、布局計(jì)算檐什、CSS 動(dòng)畫等。

頁(yè)面使用單線程的缺點(diǎn)
  • 第一個(gè)問題是如何處理高優(yōu)先級(jí)的任務(wù)弱卡。
    由于優(yōu)先級(jí)的問題使得微任務(wù)應(yīng)用而生乃正,微任務(wù)是如何權(quán)衡效率和實(shí)時(shí)性的呢?
    通常我們把消息隊(duì)列中的任務(wù)稱為宏任務(wù),每個(gè)宏任務(wù)中都包含了一個(gè)微任務(wù)隊(duì)列婶博,在執(zhí)行宏任務(wù)的過(guò)程中瓮具,如果 DOM 有變化,那么就會(huì)將該變化添加到微任務(wù)列表中凡蜻,這樣就不會(huì)影響到宏任務(wù)的繼續(xù)執(zhí)行搭综,因此也就解決了執(zhí)行效率的問題.等宏任務(wù)中的主要功能都直接完成之后,這時(shí)候划栓,渲染引擎并不著急去執(zhí)行下一個(gè)宏任務(wù)兑巾,而是執(zhí)行當(dāng)前宏任務(wù)中的微任務(wù),因?yàn)?DOM 變化的事件都保存在這些微任務(wù)隊(duì)列中忠荞,這樣也就解決了實(shí)時(shí)性問題
  • 第二個(gè)是如何解決單個(gè)任務(wù)執(zhí)行時(shí)長(zhǎng)過(guò)久的問題.
    針對(duì)這種情況蒋歌,JavaScript 可以通過(guò)回調(diào)功能來(lái)規(guī)避這種問題,也就是讓要執(zhí)行的 JavaScript 任務(wù)滯后執(zhí)行委煤。
總結(jié)

如果有一些確定好的任務(wù)堂油,可以使用一個(gè)單線程來(lái)按照順序處理這些任務(wù),這是第一版線程模型碧绞。
要在線程執(zhí)行過(guò)程中接收并處理新的任務(wù)府框,就需要引入循環(huán)語(yǔ)句和事件系統(tǒng),這是第二版線程模型讥邻。
如果要接收其他線程發(fā)送過(guò)來(lái)的任務(wù)迫靖,就需要引入消息隊(duì)列院峡,這是第三版線程模型。
如果其他進(jìn)程想要發(fā)送任務(wù)給頁(yè)面主線程系宜,那么先通過(guò) IPC 把任務(wù)發(fā)送給渲染進(jìn)程的 IO 線程照激,IO 線程再把任務(wù)發(fā)送給頁(yè)面主線程。
消息隊(duì)列機(jī)制并不是太靈活盹牧,為了適應(yīng)效率和實(shí)時(shí)性俩垃,引入了微任務(wù)。

16 | WebAPI : setTimeout是如何實(shí)現(xiàn)的


瀏覽器怎么實(shí)現(xiàn)setTimeout

通過(guò)上一小節(jié)的學(xué)習(xí)汰寓,我們知道:對(duì)于一些事件執(zhí)行的過(guò)程是:這些事件先被添加到消息隊(duì)列口柳,然后事件循環(huán)系統(tǒng)就會(huì)按照消息隊(duì)列中的順序來(lái)執(zhí)行事件。也就是說(shuō)踩寇,執(zhí)行一段異步任務(wù)啄清,需要先將任務(wù)添加到消息隊(duì)列中。
不過(guò)通過(guò)定時(shí)器設(shè)置回調(diào)函數(shù)有點(diǎn)特別俺孙,它們需要在指定的時(shí)間間隔內(nèi)被調(diào)用辣卒,但消息隊(duì)列中的任務(wù)是按照順序執(zhí)行的,所以為了保證回調(diào)函數(shù)能在指定時(shí)間內(nèi)執(zhí)行睛榄,你不能將定時(shí)器的回調(diào)函數(shù)直接添加到消息隊(duì)列中荣茫。
從Chromium隊(duì)列的部分源碼中我們知道,在Chrome中除了正常使用的消息隊(duì)列外场靴,還有另外一個(gè)消息隊(duì)列啡莉,這個(gè)隊(duì)列中維護(hù)了需要延遲執(zhí)行的任務(wù)列表,包括了定時(shí)器和Chromium內(nèi)部一些需要延遲執(zhí)行的任務(wù)旨剥。
由于消息隊(duì)列排隊(duì)和一些系統(tǒng)級(jí)別的限制咧欣,通過(guò)setTimeout設(shè)置的回調(diào)任務(wù)并非總是可以實(shí)時(shí)的執(zhí)行,這樣就不能滿足一些實(shí)時(shí)性要求較高的需求轨帜。

使用setTimeout的一些注意事項(xiàng)
  • 如果當(dāng)前任務(wù)執(zhí)行時(shí)間過(guò)久魄咕,會(huì)影響延遲到期定時(shí)器任務(wù)的執(zhí)行。
  • 如果 setTimeout 存在嵌套調(diào)用蚌父,那么系統(tǒng)會(huì)設(shè)置最短時(shí)間間隔為 4 毫秒哮兰。
  • 未激活的頁(yè)面,setTimeout 執(zhí)行最小間隔是 1000 毫秒.
  • 延時(shí)執(zhí)行時(shí)間有最大值:大約 24.8 天
  • 使用 setTimeout 設(shè)置的回調(diào)函數(shù)中的 this 不符合直覺.

17 | WebAPI:XMLHttpRequest是怎么實(shí)現(xiàn)的?


在深入講解 XMLHttpRequest 之前苟弛,我們得先介紹下同步回調(diào)異步回調(diào)這兩個(gè)概念.

回調(diào)函數(shù) VS 系統(tǒng)調(diào)用棧

回調(diào)函數(shù):將一個(gè)函數(shù)作為參數(shù)傳遞給另外一個(gè)函數(shù)喝滞,那作為參數(shù)的這個(gè)函數(shù)就是回調(diào)函數(shù)。

  • 同步回調(diào)函數(shù)代碼:
let callback = function(){
    console.log('i am do homework')
}
function doWork(cb) {
    console.log('start do work')
    cb()
    console.log('end do work')
}
doWork(callback)
//start do work
//i am do homework
//end do work
  • 異步回調(diào)函數(shù)代碼:
let callback = function(){
    console.log('i am do homework')
}
function doWork(cb) {
    console.log('start do work')
    setTimeout(cb,1000)   
    console.log('end do work')
}
doWork(callback)
XMLHttpRequest運(yùn)作機(jī)制

對(duì)回調(diào)函數(shù)有了一個(gè)認(rèn)知后膏秫,那么接著我們來(lái)分析下從發(fā)起請(qǐng)求到接收數(shù)據(jù)的完整流程:

首先從XMLHttpRequest的用法開始:

  • 第一步:創(chuàng)建XMLHttpRequest對(duì)象右遭。
  • 第二步:為xhr對(duì)象注冊(cè)回調(diào)函數(shù)。
  • 第三步:配置基礎(chǔ)的請(qǐng)求信息。
  • 第四步:發(fā)起請(qǐng)求狸演。
XMLRequest使用過(guò)程中的“坑”
  • 跨域問題
  • HTTPS混合內(nèi)容的問題:這是指HTTPS頁(yè)面中包含了不符合HTTPS安全要求的內(nèi)容言蛇,比如包含了HTTP資源。
小結(jié)

setTimeout 是直接將延遲任務(wù)添加到延遲隊(duì)列中宵距,而 XMLHttpRequest 發(fā)起請(qǐng)求,是由瀏覽器的其他進(jìn)程或者線程去執(zhí)行吨拗,然后再將執(zhí)行結(jié)果利用 IPC 的方式通知渲染進(jìn)程满哪,之后渲染進(jìn)程再將對(duì)應(yīng)的消息添加到消息隊(duì)列中。

18 | 宏任務(wù)和微任務(wù):不是所有的任務(wù)都是一個(gè)待遇


前面我們已經(jīng)知道微任務(wù)可以在實(shí)時(shí)性和效率之間做一個(gè)有效的權(quán)衡劝篷。微任務(wù)已被廣泛應(yīng)用哨鸭,比如Promise以及以Promise為基礎(chǔ)開發(fā)出來(lái)的很多其他的技術(shù)。
宏任務(wù)與微任務(wù)的區(qū)別:

宏任務(wù)

頁(yè)面中的大部分任務(wù)都是在主線程上執(zhí)行的娇妓。如渲染事件像鸡、用戶交互事件、JavaScript腳本執(zhí)行事件哈恰、網(wǎng)絡(luò)請(qǐng)求等等只估。這些在消息隊(duì)列中的任務(wù)稱為宏任務(wù)。
雖然宏任務(wù)可以滿足我們大部門的日常需求着绷,但是有時(shí)對(duì)時(shí)間精度要求較高的需求蛔钙,宏任務(wù)就難以勝任了。

微任務(wù)

微任務(wù)就是一個(gè)需要異步執(zhí)行的函數(shù)荠医,執(zhí)行時(shí)機(jī)是在主函數(shù)執(zhí)行結(jié)束之后吁脱、當(dāng)前宏任務(wù)結(jié)束之前。
產(chǎn)生微任務(wù)的兩種方式:

  • 第一種方式是使用 MutationObserver 監(jiān)控某個(gè) DOM 節(jié)點(diǎn)彬向,然后再通過(guò) JavaScript 來(lái)修改這個(gè)節(jié)點(diǎn)兼贡,或者為這個(gè)節(jié)點(diǎn)添加、刪除部分子節(jié)點(diǎn)娃胆,當(dāng) DOM 節(jié)點(diǎn)發(fā)生變化時(shí)遍希,就會(huì)產(chǎn)生 DOM 變化記錄的微任務(wù)。
  • 第二種方式是使用 Promise缕棵,當(dāng)調(diào)用 Promise.resolve() 或者 Promise.reject() 的時(shí)候孵班,也會(huì)產(chǎn)生微任務(wù)。
    通過(guò)微任務(wù)的工作流程招驴,我們可以得出如下結(jié)論:
  • 微任務(wù)和宏任務(wù)是綁定的篙程,每個(gè)宏任務(wù)在執(zhí)行時(shí),會(huì)創(chuàng)建自己的微任務(wù)隊(duì)列别厘。
  • 微任務(wù)的執(zhí)行時(shí)長(zhǎng)會(huì)影響到當(dāng)然宏任務(wù)的執(zhí)行時(shí)長(zhǎng)虱饿,因此寫代碼的時(shí)候一定要注意微任務(wù)的執(zhí)行時(shí)長(zhǎng)。
  • 在一個(gè)宏任務(wù)中,分別創(chuàng)建一個(gè)用于回調(diào)的宏任務(wù)和微任務(wù)氮发,無(wú)論什么情況下渴肉,微任務(wù)早于宏任務(wù)執(zhí)行。
監(jiān)聽DOM變化演變

微任務(wù)應(yīng)用在了MutationObserver中爽冕,MutationObserver是用來(lái)監(jiān)聽DOM變化的一套方法仇祭。 監(jiān)聽DOM變化一直是前端工程師一項(xiàng)非常核心的需求。
下面是監(jiān)聽DOM變化演變的簡(jiǎn)單總結(jié):

  • 早起觀測(cè)DOM變化就是輪詢檢測(cè)颈畸。比如使用 setTimeout 或者 setInterval 來(lái)定時(shí)檢測(cè) DOM 是否有改變乌奇。無(wú)疑這種方式實(shí)時(shí)性不好,效率還低效眯娱。
  • 2000年的時(shí)候引入了Mutation Event礁苗,Mutation Event采用了觀察者的設(shè)計(jì)模式,當(dāng)DOM有變動(dòng)時(shí)立即出發(fā)相應(yīng)的事件徙缴。此方式屬于同步回調(diào)试伙。雖然這種方式解決了實(shí)時(shí)性問題,但是因?yàn)闀?huì)產(chǎn)生較大性能開銷于样、導(dǎo)致頁(yè)面性能出現(xiàn)問題疏叨,被反對(duì)使用并逐步從web標(biāo)準(zhǔn)事件中刪除。
  • MutationObserver替代MutationEvent百宇,相較于Event方式考廉,Observer采用了一次觸發(fā)異步回調(diào)。且采用微任務(wù)的處理携御,使得實(shí)時(shí)性與性能功能都得到有效提高昌粤。

19 | Promise:使用Promise,告別回調(diào)函數(shù)

微任務(wù)的另一個(gè)應(yīng)用:Promise啄刹。
本節(jié)簡(jiǎn)單介紹JavaScript引入Promise的動(dòng)機(jī)涮坐,以及解決問題的幾個(gè)核心關(guān)鍵點(diǎn)。
講到動(dòng)機(jī)誓军,也就是說(shuō)Promise解決了什么問題袱讹。眾所周知,他解決的是異步編碼風(fēng)格的問題昵时。

頁(yè)面編程的一大特點(diǎn)就是:異步編程捷雕,下面分析異步編程的代碼風(fēng)格進(jìn)化。

  • 之前的代碼編碼風(fēng)格壹甥,一段代碼可能會(huì)出現(xiàn)五次回調(diào)救巷,這種回調(diào)導(dǎo)致代碼邏輯不連貫、不連線句柠,不符合人的直覺浦译。
  • 然后開發(fā)人員們通過(guò)封裝異步代碼棒假,讓處理流程變得線性,但是這種處理方式如果嵌套了太多的回調(diào)函數(shù)就容易陷入回調(diào)地獄精盅。
  • 陷入回調(diào)地獄的后代碼看上去很亂主要是兩點(diǎn):嵌套調(diào)用和任務(wù)不確定性(成功或者失敗)帽哑。于是Promise出現(xiàn),解決了這兩個(gè)問題叹俏。
Promise:消滅嵌套調(diào)用和多次錯(cuò)誤處理

Promise通過(guò)兩步解決嵌套回調(diào)問題:

  • 首先妻枕,Promise實(shí)現(xiàn)了回調(diào)函數(shù)的延時(shí)綁定(.then)
  • 其次,將回調(diào)函數(shù)返回值穿透到最外層她肯。

Promise處理異常:
通過(guò)最后一個(gè)catch佳头,將所有對(duì)象合并到一個(gè)函數(shù)來(lái)處理之前的所有異常。

Promise與微任務(wù)

Promise 之所以要使用微任務(wù)是由 Promise 回調(diào)函數(shù)延遲綁定技術(shù)導(dǎo)致的晴氨。

20 | async/await:使用同步的方式去寫異步代碼

當(dāng)Promise解決回調(diào)地獄代碼風(fēng)格的同時(shí),我們發(fā)現(xiàn)寫很多的then函數(shù)碉输,還是有些不太容易閱讀籽前。
基于這個(gè)原因,ES7引入了async/await敷钾,這是JavaScript異步編程的一個(gè)重大改進(jìn)枝哄,提供了在不阻塞主線程的情況下使用同步代碼實(shí)現(xiàn)異步訪問資源的能力。并且使得代碼邏輯更加清晰阻荒。

本節(jié)首先介紹生成器(Generator)是如何工作的挠锥,接著介紹了Generator的底層實(shí)現(xiàn)機(jī)制--協(xié)程。
這是因?yàn)閍sync/await使用了Generator和Promise兩種技術(shù)侨赡。所以緊接著通過(guò)Generator和Promise來(lái)分析async/await到底是如何通過(guò)以同步方式來(lái)編寫異步代碼的蓖租。

生成器 VS 協(xié)程

生成器函數(shù):生成器函數(shù)是一個(gè)帶星號(hào)函數(shù),而且是可以暫停執(zhí)行和恢復(fù)執(zhí)行的羊壹。
具體使用方式就是:在生成器函數(shù)內(nèi)部執(zhí)行一段代碼蓖宦,若遇到y(tǒng)iled關(guān)鍵字,那JS引擎將返回該關(guān)鍵字后面的內(nèi)容且暫停該函數(shù)執(zhí)行油猫,外部函數(shù)通過(guò)next方法恢復(fù)函數(shù)的執(zhí)行稠茂。
那么JavaScript引擎V8是如何實(shí)現(xiàn)一個(gè)函數(shù)的暫停和恢復(fù)的?

搞懂它的暫停和恢復(fù)情妖,需要首先了解協(xié)程的概念睬关。協(xié)程是一種比線程更加輕量級(jí)的存在≌敝ぃ可以把協(xié)程看作是跑在線程上的任務(wù)电爹,一個(gè)線程可以存在多個(gè)協(xié)程。但在線程上同時(shí)只能執(zhí)行一個(gè)協(xié)程情竹。
在JS中藐不,生成器就是協(xié)程的一種實(shí)現(xiàn)方式匀哄。

asnyc/await

為了更近一步改進(jìn)生成器代碼,ES7引入了async/awit雏蛮,實(shí)現(xiàn)了更加直觀簡(jiǎn)潔的代碼涎嚼。
async/aswit技術(shù)背后的實(shí)現(xiàn)就是Promise和生成器應(yīng)用。往底層說(shuō)就是微服務(wù)和協(xié)程應(yīng)用挑秉。

async:是一個(gè)通過(guò)異步執(zhí)行并隱式返回Promise作為結(jié)果的函數(shù)法梯。
await:我們知道了 async 函數(shù)返回的是一個(gè) Promise 對(duì)象,那下面我們?cè)俳Y(jié)合文中這段代碼來(lái)看看 await 到底是什么犀概。

async function foo() {
    console.log(1)
    let a = await 100
    console.log(a)
    console.log(2)
}
console.log(0)
foo()
console.log(3)
//輸出結(jié)果:0 3 100 2

async/await 無(wú)疑是異步編程領(lǐng)域非常大的一個(gè)革新立哑,也是未來(lái)的一個(gè)主流的編程風(fēng)格。其實(shí)姻灶,除了 JavaScript铛绰,Python、Dart产喉、C# 等語(yǔ)言也都引入了 async/await捂掰,使用它不僅能讓代碼更加整潔美觀,而且還能確保該函數(shù)始終都能返回 Promise曾沈。

世界有多大这嚣,取決于你認(rèn)識(shí)和見過(guò)多少人和事。

如有疑問請(qǐng)?zhí)砑游业奈⑿盘?hào):18231133236塞俱。歡迎交流姐帚!
更多內(nèi)容,請(qǐng)?jiān)L問的我的個(gè)人博客:https://www.liugezhou.online.
您也可以關(guān)注我的個(gè)人公眾號(hào):【Dangerous Wakaka】

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末障涯,一起剝皮案震驚了整個(gè)濱河市罐旗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌像樊,老刑警劉巖尤莺,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異生棍,居然都是意外死亡颤霎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門涂滴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)友酱,“玉大人,你說(shuō)我怎么就攤上這事柔纵〉奚迹” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵搁料,是天一觀的道長(zhǎng)或详。 經(jīng)常有香客問我系羞,道長(zhǎng),這世上最難降的妖魔是什么霸琴? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任椒振,我火速辦了婚禮,結(jié)果婚禮上梧乘,老公的妹妹穿的比我還像新娘澎迎。我一直安慰自己,他們只是感情好选调,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布夹供。 她就那樣靜靜地躺著,像睡著了一般仁堪。 火紅的嫁衣襯著肌膚如雪哮洽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天弦聂,我揣著相機(jī)與錄音袁铐,去河邊找鬼。 笑死横浑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屉更。 我是一名探鬼主播徙融,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瑰谜!你這毒婦竟也來(lái)了欺冀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤萨脑,失蹤者是張志新(化名)和其女友劉穎隐轩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渤早,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡职车,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鹊杖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悴灵。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖骂蓖,靈堂內(nèi)的尸體忽然破棺而出积瞒,到底是詐尸還是另有隱情,我是刑警寧澤登下,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布茫孔,位于F島的核電站叮喳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缰贝。R本人自食惡果不足惜馍悟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揩瞪。 院中可真熱鬧赋朦,春花似錦、人聲如沸李破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嗤攻。三九已至毛嫉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妇菱,已是汗流浹背承粤。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闯团,地道東北人辛臊。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像房交,于是被迫代替她去往敵國(guó)和親彻舰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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