【前端進(jìn)階】深入淺出瀏覽器事件循環(huán)

引子:為什么會(huì)有事件循環(huán)

重點(diǎn): javascript 從誕生之日起就是一門單線程的非阻塞的腳本語(yǔ)言

我們先來(lái)聊下 JavaScript 這兩個(gè)特點(diǎn):

  • 單線程: JavaScript 是單線程的妻怎,單線程是指 JavaScript 引擎中解析和執(zhí)行 JavaScript 代碼的線程只有一個(gè)(主線程),每次只能做一件事情。單線程存在是必然的钠右,在瀏覽器中助析, 如果 javascript 是多線程的误辑,那么當(dāng)兩個(gè)線程同時(shí)對(duì) dom 進(jìn)行一項(xiàng)操作散址,例如一個(gè)向其添加事件霎桅,而另一個(gè)刪除了這個(gè) dom,這個(gè)時(shí)候其實(shí)是矛盾的

  • 非阻塞: 當(dāng)我們的 Javascript 代碼運(yùn)行一個(gè)異步任務(wù)的時(shí)候(像 Ajax 等)产园,主線程會(huì)掛起這個(gè)任務(wù)汞斧,然后異步任務(wù)返回結(jié)果的時(shí)候再根據(jù)特定的結(jié)果去執(zhí)行相應(yīng)的回調(diào)函數(shù)

如何做到非阻塞呢夜郁?這就需要我們的主角——事件循環(huán)(Event Loop

瀏覽器中的事件循環(huán)

我們看一個(gè)很經(jīng)典的圖,這張圖基本可以概括了事件循環(huán)(該圖來(lái)自演講—— 菲利普·羅伯茨:到底什么是Event Loop呢断箫? | 歐洲 JSConf 2014[1])后面演示用的 Loupe[2] 也是該演講者寫的((Loupe是一種可視化工具拂酣,可以幫助您了解JavaScript的調(diào)用堆棧/事件循環(huán)/回調(diào)隊(duì)列如何相互影響))

[圖片上傳失敗...(image-e56a0a-1601973516487)]

當(dāng) javascript 代碼執(zhí)行的時(shí)候會(huì)將不同的變量存于內(nèi)存中的不同位置:堆(heap)和棧(stack)中來(lái)加以區(qū)分秋冰。其中仲义,堆里存放著一些對(duì)象。而棧中則存放著一些基礎(chǔ)類型變量以及對(duì)象的指針

執(zhí)行棧(call stack: 當(dāng)我們調(diào)用一個(gè)方法的時(shí)候剑勾,js會(huì)生成一個(gè)與這個(gè)方法對(duì)應(yīng)的執(zhí)行環(huán)境(context)埃撵,又叫執(zhí)行上下文。這個(gè)執(zhí)行環(huán)境中存在著這個(gè)方法的私有作用域虽另,上層作用域的指向暂刘,方法的參數(shù),這個(gè)作用域中定義的變量以及這個(gè)作用域的this對(duì)象捂刺。 而當(dāng)一系列方法被依次調(diào)用的時(shí)候谣拣,因?yàn)閖s是單線程的,同一時(shí)間只能執(zhí)行一個(gè)方法族展,于是這些方法被排隊(duì)在一個(gè)單獨(dú)的地方森缠。這個(gè)地方被稱為執(zhí)行棧

比如,如下是一段同步代碼的執(zhí)行

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">function a() { b(); console.log('a'); } function b() { console.log('b') } a(); </pre>

我們通過 Loupe 演示下代碼的執(zhí)行過程:

[圖片上傳失敗...(image-3c4ea4-1601973516487)]

  • 執(zhí)行函數(shù) a()先入棧
  • a()中先執(zhí)行函數(shù) b() 函數(shù)b() 入棧
  • 執(zhí)行函數(shù)b(), console.log('b') 入棧
  • 輸出 b仪缸, console.log('b')出棧
  • 函數(shù)b() 執(zhí)行完成贵涵,出棧
  • console.log('a') 入棧,執(zhí)行恰画,輸出 a, 出棧
  • 函數(shù)a 執(zhí)行完成宾茂,出棧

同步代碼的執(zhí)行過程是相對(duì)比較簡(jiǎn)單的,但涉及到異步執(zhí)行的話拴还,又是怎樣的呢跨晴?

事件隊(duì)列(callback queue): js 引擎遇到一個(gè)異步事件后并不會(huì)一直等待其返回結(jié)果,而是會(huì)將這個(gè)事件掛起片林,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)端盆。當(dāng)一個(gè)異步事件返回結(jié)果后,js 會(huì)將這個(gè)事件加入與當(dāng)前執(zhí)行棧不同的另一個(gè)隊(duì)列拇厢,我們稱之為事件隊(duì)列

被放入事件隊(duì)列不會(huì)立刻執(zhí)行起回調(diào)爱谁,而是等待當(dāng)前執(zhí)行棧中所有任務(wù)都執(zhí)行完畢,主線程空閑狀態(tài)孝偎,主線程會(huì)去查找事件隊(duì)列中是否有任務(wù)访敌,如果有,則取出排在第一位的事件衣盾,并把這個(gè)事件對(duì)應(yīng)的回調(diào)放到執(zhí)行棧中寺旺,然后執(zhí)行其中的同步代碼

Loupe 官方的一個(gè)例子:

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`$.on('button', 'click', function onClick() {
setTimeout(function timer() {
console.log('You clicked the button!');
}, 2000);
});

console.log("Hi!");

setTimeout(function timeout() {
console.log("Click the button!");
}, 5000);

console.log("Welcome to loupe.");` </pre>

[圖片上傳失敗...(image-d78414-1601973516487)]

我們分析一下這個(gè)執(zhí)行的過程:

  • 首先是爷抓,注冊(cè)了點(diǎn)擊事件,異步執(zhí)行阻塑,這個(gè)時(shí)候會(huì)將它放在 Web Api
  • console.log("Hi!") 入棧蓝撇,直接執(zhí)行,輸出 Hi
  • 執(zhí)行 setTimeout陈莽,異步執(zhí)行渤昌,將其掛載起來(lái)
  • 執(zhí)行 console.log("Welcome to loupe."), 輸出 Welcome to loupe.
  • 5 秒鐘后走搁,setTimeout 執(zhí)行回調(diào)独柑,將回調(diào)放入到事件隊(duì)列中,一旦主線程空閑私植,則取出運(yùn)行
  • 我點(diǎn)擊了按鈕【這里我只操作了一次】忌栅,觸發(fā)了點(diǎn)擊事件,將點(diǎn)擊事件的回調(diào)放入到事件隊(duì)列中曲稼,一旦主線程空閑索绪,則取出運(yùn)行
  • 運(yùn)行點(diǎn)擊事件回調(diào)中的 setTimeout
  • 2 秒鐘后,setTimeout 執(zhí)行回調(diào)贫悄,將回調(diào)放入到事件隊(duì)列中瑞驱,一旦主線程空閑,則取出運(yùn)行

再回頭看看這張圖清女,應(yīng)該有種豁然開朗的感覺

[圖片上傳失敗...(image-adf411-1601973516487)]

以上的過程按照類似如下的方式實(shí)現(xiàn)钱烟,queue.waitForMessage() 會(huì)同步地等待消息到達(dá)(如果當(dāng)前沒有任何消息等待被處理),故我們稱之為事件循環(huán)(Event Loop

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">while (queue.waitForMessage()) { queue.processNextMessage(); } </pre>

微任務(wù)和宏任務(wù)

微任務(wù)——Micro-Task

常見的 micro-task:new Promise().then(callback)嫡丙、MutationObserve 等(asyncawait)實(shí)際上是 Promise 的語(yǔ)法糖

宏任務(wù)——Macro-Task

常見的 macro-tasksetTimeout拴袭、setIntervalscript(整體代碼)曙博、 I/O 操作拥刻、UI 交互事件、postMessage

事件循環(huán)的執(zhí)行順序

異步任務(wù)的返回結(jié)果會(huì)被放到一個(gè)事件隊(duì)列中父泳,根據(jù)上面提到的異步事件的類型般哼,這個(gè)事件實(shí)際上會(huì)被放到對(duì)應(yīng)的宏任務(wù)和微任務(wù)隊(duì)列中去

Eveent Loop 的循環(huán)過程如下:

  • 執(zhí)行一個(gè)宏任務(wù)(一般一開始是整體代碼(script)),如果沒有可選的宏任務(wù)惠窄,則直接處理微任務(wù)
  • 執(zhí)行過程中如果遇到微任務(wù)蒸眠,就將它添加到微任務(wù)的任務(wù)隊(duì)列中
  • 執(zhí)行過程中如果遇到宏任務(wù),就將它添加到宏任務(wù)的任務(wù)隊(duì)列中
  • 執(zhí)行一個(gè)宏任務(wù)完成之后杆融,就需要檢測(cè)微任務(wù)隊(duì)列有沒有需要執(zhí)行的任務(wù)楞卡,有的話,全部執(zhí)行,沒有的話蒋腮,進(jìn)入下一步
  • 檢查渲染淘捡,然后 GUI 線程接管渲染,進(jìn)行瀏覽器渲染
  • 渲染完畢后池摧,JS線程繼續(xù)接管焦除,開始下一個(gè)宏任務(wù)...(循環(huán)上面的步驟)

如下圖所示:

[圖片上傳失敗...(image-3801f0-1601973516486)]

執(zhí)行順序總結(jié):執(zhí)行宏任務(wù),然后執(zhí)行該宏任務(wù)產(chǎn)生的微任務(wù)作彤,若微任務(wù)在執(zhí)行過程中產(chǎn)生了新的微任務(wù)膘魄,則繼續(xù)執(zhí)行微任務(wù),微任務(wù)執(zhí)行完畢后宦棺,再回到宏任務(wù)中進(jìn)行下一輪循環(huán)

[圖片上傳失敗...(image-29d6f4-1601973516486)]

為了更好的理解瓣距,我們來(lái)看一個(gè)例子

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`console.log('start')

setTimeout(function() {
console.log('setTimeout')
}, 0)

Promise.resolve().then(function() {
console.log('promise1')
}).then(function() {
console.log('promise2')
})

console.log('end')` </pre>

[圖片上傳失敗...(image-533012-1601973516486)]

我們來(lái)分析一下:

  • 執(zhí)行全局 script黔帕,輸出 start
  • 執(zhí)行 setTimeout 壓入 macrotask 隊(duì)列代咸,promise.then 回調(diào)放入 microtask 隊(duì)列,最后執(zhí)行 console.log('end')成黄,輸出 end
  • 全局 script 屬于宏任務(wù)呐芥,執(zhí)行完成那接下來(lái)就是執(zhí)行 microtask 隊(duì)列的任務(wù)了,執(zhí)行 promise 回調(diào)打印 promise1
  • promise 回調(diào)函數(shù)默認(rèn)返回 undefined奋岁,promise 狀態(tài)變?yōu)?fullfill 觸發(fā)接下來(lái)的 then 回調(diào)思瘟,繼續(xù)壓入 microtask 隊(duì)列,event loop 會(huì)把當(dāng)前的microtask 隊(duì)列一直執(zhí)行完闻伶,此時(shí)執(zhí)行第二個(gè)promise.then` 回調(diào)打印出promise2
  • 這時(shí) microtask 隊(duì)列已經(jīng)為空滨攻,接下來(lái)主線程會(huì)去做一些 UI 渲染工作(不一定會(huì)做),然后開始下一輪 event loop蓝翰,執(zhí)行 setTimeout 的回調(diào)光绕,打印出 setTimeout

故最后的結(jié)果如下:

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">start end promise1 promise2 setTimeout </pre>

練習(xí)題

增加這個(gè)環(huán)境在于,現(xiàn)在面試筆試都會(huì)出事件循環(huán)的題目畜份,實(shí)際上的可能比上面的例子難诞帐,原因在于微任務(wù)和宏任務(wù)涉及的知識(shí)點(diǎn)不少,這就需要我們進(jìn)一步鞏固我們的基礎(chǔ)知識(shí)爆雹,我相信能夠認(rèn)真對(duì)待以下題目的停蕉,都能夠更好的掌握事件循環(huán)

我就暫不做分析,大家不懂的有疑問的可以在評(píng)論區(qū)一起交流

題目一

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`console.log('start');
setTimeout(() => {
console.log('children2');
Promise.resolve().then(() => {
console.log('children3');
})
}, 0);

new Promise(function(resolve, reject) {
console.log('children4');
setTimeout(function() {
console.log('children5');
resolve('children6')
}, 0)
}).then((res) => {
console.log('children7');
setTimeout(() => {
console.log(res);
}, 0)
})` </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> start children4 children2 children3 children5 children7</details>

題目2

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`const p = function() {
return new Promise((resolve, reject) => {
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 0)
resolve(2)
})
p1.then((res) => {
console.log(res);
})
console.log(3);
resolve(4);
})
}

p().then((res) => {
console.log(res);
})
console.log('end');` </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> 3 end 2 4</details>

題目3

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">async function async1(){ console.log('async1 start') await async2() console.log('async1 end') } async function async2(){ console.log('async2') } console.log('script start') setTimeout(function(){ console.log('setTimeout') },0) async1(); new Promise(function(resolve){ console.log('promise1') resolve(); }).then(function(){ console.log('promise2') }) console.log('script end') </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> script start async1 start async2 promise1 script end async1 end promise2 setTimeout</details>

題目4

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">let resolvePromise = new Promise(resolve => { let resolvedPromise = Promise.resolve() resolve(resolvedPromise); // 提示:resolve(resolvedPromise) 等同于: // Promise.resolve().then(() => resolvedPromise.then(resolve)); }) resolvePromise.then(() => { console.log('resolvePromise resolved') }) let resolvedPromiseThen = Promise.resolve().then(res => { console.log('promise1') }) resolvedPromiseThen .then(() => { console.log('promise2') }) .then(() => { console.log('promise3') }) </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> promise1 -> promise2 -> resolvePromise resolved -> promise3</details>

題目5

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`console.log('script start');

setTimeout(() => {
console.log('Gopal');
}, 1 * 2000);

Promise.resolve()
.then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});

async function foo() {
await bar()
console.log('async1 end')
}
foo()

async function errorFunc () {
try {
// Tips:參考:https://zh.javascript.info/promise-error-handling:隱式 try…catch
// Promise.reject()方法返回一個(gè)帶有拒絕原因的Promise對(duì)象
// Promise.reject('error!!!') === new Error('error!!!')
await Promise.reject('error!!!')
} catch(e) {
console.log(e)
}
console.log('async1');
return Promise.resolve('async1 success')
}
errorFunc().then(res => console.log(res))

function bar() {
console.log('async2 end')
}

console.log('script end');` </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> script start async2 end script end promise1 async1 end error!!! async1 promise2 async1 success Gopal</details>

題目6

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">new Promise((resolve, reject) => { console.log(1) resolve() }) .then(() => { console.log(2) new Promise((resolve, reject) => { console.log(3) setTimeout(() => { reject(); }, 3 * 1000); resolve() }) .then(() => { console.log(4) new Promise((resolve, reject) => { console.log(5) resolve(); }) .then(() => { console.log(7) }) .then(() => { console.log(9) }) }) .then(() => { console.log(8) }) }) .then(() => { console.log(6) }) </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> 1 2 3 4 5 6 7 8 9</details>

題目7

<pre class="custom" data-tool="mdnice編輯器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`console.log('1');

setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
})
new Promise((resolve) => {
console.log('4');
resolve();
}).then(() => {
console.log('5')
})
})

Promise.reject().then(() => {
console.log('13');
}, () => {
console.log('12');
})

new Promise((resolve) => {
console.log('7');
resolve();
}).then(() => {
console.log('8')
})

setTimeout(() => {
console.log('9');
Promise.resolve().then(() => {
console.log('10');
})
new Promise((resolve) => {
console.log('11');
resolve();
}).then(() => {
console.log('12')
})
})` </pre>

<details data-tool="mdnice編輯器"><summary>點(diǎn)擊查看答案</summary> 1 7 12 8 2 4 9 11 3 5 10 12</details>

總結(jié)

本文從 JS 的兩個(gè)特點(diǎn):?jiǎn)尉€程以及非阻塞介紹了事件循環(huán)的必要性钙态,因?yàn)槭录h(huán)在瀏覽器和 Node.js 的表現(xiàn)是很大不一樣的慧起,本人只談?wù)摰搅藶g覽器中的事件循環(huán),并介紹了微任務(wù)和宏任務(wù)册倒,以及它們的執(zhí)行流程蚓挤,最后通過 7 道題目幫助大家鞏固知識(shí)

大家喜歡的話,別忘了點(diǎn)贊關(guān)注~

往期優(yōu)秀文章推薦

  • 一個(gè)合格的中級(jí)前端工程師應(yīng)該掌握的 20 個(gè) Vue 技巧[3]
  • 【Vue進(jìn)階】——如何實(shí)現(xiàn)組件屬性透?jìng)鳎?sup>[4]
  • 前端應(yīng)該知道的 HTTP 知識(shí)【金九銀十必備】[5]
  • 最強(qiáng)大的 CSS 布局 —— Grid 布局[6]
  • 如何用 Typescript 寫一個(gè)完整的 Vue 應(yīng)用程序[7]
  • 前端應(yīng)該知道的web調(diào)試工具——whistle[8]

參考

詳解JavaScript中的Event Loop(事件循環(huán))機(jī)制[9]

深入理解NodeJS事件循環(huán)機(jī)制[10]

并發(fā)模型與事件循環(huán)[11]

【前端體系】從一道面試題談?wù)剬?duì)EventLoop的理解[12]

菲利普·羅伯茨:到底什么是Event Loop呢? | 歐洲 JSConf 2014[13]

JavaScript中的Event Loop(事件循環(huán))機(jī)制[14]

JS事件循環(huán)機(jī)制(event loop)之宏任務(wù)/微任務(wù)[15]

深入理解js事件循環(huán)機(jī)制(瀏覽器篇)[16]

從面試題看 JS 事件循環(huán)與 macro micro 任務(wù)隊(duì)列[17]

參考資料

[1]

菲利普·羅伯茨:到底什么是Event Loop呢屈尼? | 歐洲 JSConf 2014: https://www.youtube.com/watch?v=8aGhZQkoFbQ [2]

Loupe: http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D [3]

一個(gè)合格的中級(jí)前端工程師應(yīng)該掌握的 20 個(gè) Vue 技巧: https://juejin.im/post/6872128694639394830 [4]

【Vue進(jìn)階】——如何實(shí)現(xiàn)組件屬性透?jìng)鳎? https://juejin.im/post/6865451649817640968 [5]

前端應(yīng)該知道的 HTTP 知識(shí)【金九銀十必備】: https://juejin.im/post/6864119706500988935 [6]

最強(qiáng)大的 CSS 布局 —— Grid 布局: https://juejin.im/post/6854573220306255880 [7]

如何用 Typescript 寫一個(gè)完整的 Vue 應(yīng)用程序: https://juejin.im/post/6860703641037340686 [8]

前端應(yīng)該知道的web調(diào)試工具——whistle: https://juejin.im/post/6861882596927504392 [9]

詳解JavaScript中的Event Loop(事件循環(huán))機(jī)制: https://zhuanlan.zhihu.com/p/33058983 [10]

深入理解NodeJS事件循環(huán)機(jī)制: https://juejin.im/post/6844903999506923528 [11]

并發(fā)模型與事件循環(huán): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop [12]

【前端體系】從一道面試題談?wù)剬?duì)EventLoop的理解: https://juejin.im/post/6868849475008331783 [13]

菲利普·羅伯茨:到底什么是Event Loop呢册着? | 歐洲 JSConf 2014: https://www.youtube.com/watch?v=8aGhZQkoFbQ [14]

JavaScript中的Event Loop(事件循環(huán))機(jī)制: https://segmentfault.com/a/1190000022805523 [15]

JS事件循環(huán)機(jī)制(event loop)之宏任務(wù)/微任務(wù): https://juejin.im/post/6844903638238756878 [16]

深入理解js事件循環(huán)機(jī)制(瀏覽器篇): http://lynnelv.github.io/js-event-loop-browser [17]

從面試題看 JS 事件循環(huán)與 macro micro 任務(wù)隊(duì)列: https://juejin.im/post/6844903796754104334

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市脾歧,隨后出現(xiàn)的幾起案子甲捏,更是在濱河造成了極大的恐慌,老刑警劉巖鞭执,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件司顿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡兄纺,警方通過查閱死者的電腦和手機(jī)大溜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)估脆,“玉大人钦奋,你說(shuō)我怎么就攤上這事「碓” “怎么了付材?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)圃阳。 經(jīng)常有香客問我厌衔,道長(zhǎng),這世上最難降的妖魔是什么捍岳? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任富寿,我火速辦了婚禮,結(jié)果婚禮上锣夹,老公的妹妹穿的比我還像新娘页徐。我一直安慰自己,他們只是感情好晕城,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布泞坦。 她就那樣靜靜地躺著,像睡著了一般砖顷。 火紅的嫁衣襯著肌膚如雪贰锁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天滤蝠,我揣著相機(jī)與錄音豌熄,去河邊找鬼。 笑死物咳,一個(gè)胖子當(dāng)著我的面吹牛锣险,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼芯肤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巷折!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起崖咨,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锻拘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后击蹲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體署拟,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年歌豺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了推穷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡类咧,死狀恐怖馒铃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轮听,我是刑警寧澤骗露,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站血巍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏珊随。R本人自食惡果不足惜述寡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叶洞。 院中可真熱鬧鲫凶,春花似錦、人聲如沸衩辟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艺晴。三九已至昼钻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間封寞,已是汗流浹背然评。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狈究,地道東北人碗淌。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亿眠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碎罚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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