Flutter之Future 異步await sync 終結(jié)者

20年圣誕

2020 神奇的一年众弓,載入史冊(cè)的一年业簿,改變了很多人的命運(yùn)壁却,曼谷第一開(kāi)膛手也轉(zhuǎn)行入坑Flutter批狱,廢話不多說(shuō),干就完了

Event Loop 機(jī)制

像iOS runloop一樣展东,flutter也有事件循環(huán)精耐,不同的是,那就是 Dart 是單線程的琅锻。那單線程意味著什么呢卦停?這意味著 Dart 代碼是有序的,按照在 main 函數(shù)出現(xiàn)的次序一個(gè)接一個(gè)地執(zhí)行恼蓬,不會(huì)被其他代碼中斷惊完。另外,作為支持 Flutter 這個(gè) UI 框架的關(guān)鍵技術(shù)处硬,Dart 當(dāng)然也支持異步小槐。需要注意的是,單線程和異步并不沖突荷辕。

為什么單線程也可以異步凿跳?

比如說(shuō),網(wǎng)絡(luò)請(qǐng)求疮方,Socket 本身提供了 select 模型可以異步查詢控嗜;而文件 IO,操作系統(tǒng)也提供了基于事件的回調(diào)機(jī)制骡显。

基于這些特點(diǎn)疆栏,單線程模型可以在等待的過(guò)程中做別的事情,等真正需要響應(yīng)結(jié)果了惫谤,再去做對(duì)應(yīng)的處理壁顶。因?yàn)榈却^(guò)程并不是阻塞的,所以給我們的感覺(jué)就像是同時(shí)在做多件事情一樣溜歪。但其實(shí)始終只有一個(gè)線程在處理你的事情若专。

等待這個(gè)行為是通過(guò) Event Loop 驅(qū)動(dòng)的。事件隊(duì)列 Event Queue 會(huì)把其他平行世界(比如 Socket)完成的蝴猪,需要主線程響應(yīng)的事件放入其中调衰。像其他語(yǔ)言一樣膊爪,Dart 也有一個(gè)巨大的事件循環(huán),在不斷的輪詢事件隊(duì)列窖式,取出事件(比如,鍵盤事件动壤、I\O 事件萝喘、網(wǎng)絡(luò)事件等),在主線程同步執(zhí)行其回調(diào)函數(shù)琼懊,如下圖所示:

Event Loop
異步任務(wù)

圖 1 的 Event Loop 示意圖只是一個(gè)簡(jiǎn)化版阁簸。在 Dart 中,實(shí)際上有兩個(gè)隊(duì)列哼丈,一個(gè)事件隊(duì)列(Event Queue)启妹,另一個(gè)則是微任務(wù)隊(duì)列(Microtask Queue)。在每一次事件循環(huán)中醉旦,Dart 總是先去第一個(gè)微任務(wù)隊(duì)列中查詢是否有可執(zhí)行的任務(wù)饶米,有的話會(huì)處理完所有的任務(wù)。如果沒(méi)有车胡,才會(huì)處理后續(xù)的事件隊(duì)列的流程檬输。

Event Loop 完整版的流程圖,應(yīng)該如下所示:


Microtask Queue 與 Event Queue

首先匈棘,我們看看微任務(wù)隊(duì)列丧慈。微任務(wù)顧名思義,表示一個(gè)短時(shí)間內(nèi)就會(huì)完成的異步任務(wù)主卫。從上面的流程圖可以看到逃默,微任務(wù)隊(duì)列在事件循環(huán)中的優(yōu)先級(jí)是最高的,只要隊(duì)列中還有任務(wù)簇搅,就可以一直霸占著事件循環(huán)完域。

微任務(wù)是由 scheduleMicroTask 建立的。如下所示瘩将,這段代碼會(huì)在下一個(gè)事件循環(huán)中輸出一段字符串:


scheduleMicrotask(() => print('This is a microtask'));

一般的異步任務(wù)通常也很少必須要在事件隊(duì)列前完成筒主,所以也不需要太高的優(yōu)先級(jí),因此我們通常很少會(huì)直接用到微任務(wù)隊(duì)列鸟蟹,就連 Flutter 內(nèi)部乌妙,也只有 7 處用到了而已(比如,手勢(shì)識(shí)別建钥、文本輸入藤韵、滾動(dòng)視圖、保存頁(yè)面效果等需要高優(yōu)執(zhí)行任務(wù)的場(chǎng)景)熊经。

異步任務(wù)我們用的最多的還是優(yōu)先級(jí)更低的 Event Queue泽艘。比如欲险,I/O、繪制匹涮、定時(shí)器這些異步事件天试,都是通過(guò)事件隊(duì)列驅(qū)動(dòng)主線程執(zhí)行的。

Dart 為 Event Queue 的任務(wù)建立提供了一層封裝然低,叫作 Future喜每。從名字上也很容易理解,它表示一個(gè)在未來(lái)時(shí)間才會(huì)完成的任務(wù)雳攘。

把一個(gè)函數(shù)體放入 Future带兜,就完成了從同步任務(wù)到異步任務(wù)的包裝。Future 還提供了鏈?zhǔn)秸{(diào)用的能力吨灭,可以在異步任務(wù)執(zhí)行完畢后依次執(zhí)行鏈路上的其他函數(shù)體刚照。

接下來(lái),我們看一個(gè)具體的代碼示例:分別聲明兩個(gè)異步任務(wù)喧兄,在下一個(gè)事件循環(huán)中輸出一段字符串无畔。其中第二個(gè)任務(wù)執(zhí)行完畢之后,還會(huì)繼續(xù)輸出另外兩段字符串:


Future(() => print('Running in Future 1'));//下一個(gè)事件循環(huán)輸出字符串

Future(() => print(‘Running in Future 2'))
  .then((_) => print('and then 1'))
  .then((_) => print('and then 2’));//上一個(gè)事件循環(huán)結(jié)束后吠冤,連續(xù)輸出三段字符串

當(dāng)然檩互,這兩個(gè) Future 異步任務(wù)的執(zhí)行優(yōu)先級(jí)比微任務(wù)的優(yōu)先級(jí)要低。

正常情況下咨演,一個(gè) Future 異步任務(wù)的執(zhí)行是相對(duì)簡(jiǎn)單的:在我們聲明一個(gè) Future 時(shí)闸昨,Dart 會(huì)將異步任務(wù)的函數(shù)執(zhí)行體放入事件隊(duì)列,然后立即返回薄风,后續(xù)的代碼繼續(xù)同步執(zhí)行饵较。而當(dāng)同步執(zhí)行的代碼執(zhí)行完畢后,事件隊(duì)列會(huì)按照加入事件隊(duì)列的順序(即聲明順序)遭赂,依次取出事件循诉,最后同步執(zhí)行 Future 的函數(shù)體及后續(xù)的 then。

這意味著撇他,then 與 Future 函數(shù)體共用一個(gè)事件循環(huán)茄猫。而如果 Future 有多個(gè) then,它們也會(huì)按照鏈?zhǔn)秸{(diào)用的先后順序同步執(zhí)行困肩,同樣也會(huì)共用一個(gè)事件循環(huán)划纽。

如果 Future 執(zhí)行體已經(jīng)執(zhí)行完畢了,但你又拿著這個(gè) Future 的引用锌畸,往里面加了一個(gè) then 方法體勇劣,這時(shí) Dart 會(huì)如何處理呢?面對(duì)這種情況,Dart 會(huì)將后續(xù)加入的 then 方法體放入微任務(wù)隊(duì)列比默,盡快執(zhí)行幻捏。

下面的代碼演示了 Future 的執(zhí)行規(guī)則,即命咐,先加入事件隊(duì)列篡九,或者先聲明的任務(wù)先執(zhí)行;then 在 Future 結(jié)束后立即執(zhí)行醋奠。


//f1比f(wàn)2先執(zhí)行
Future(() => print('f1'));
Future(() => print('f2'));

//f3執(zhí)行后會(huì)立刻同步執(zhí)行then 3
Future(() => print('f3')).then((_) => print('then 3'));

//then 4會(huì)加入微任務(wù)隊(duì)列榛臼,盡快執(zhí)行
Future(() => null).then((_) => print('then 4'));
  • 在第一個(gè)例子中,由于 f1 比 f2 先聲明钝域,因此會(huì)被先加入事件隊(duì)列讽坏,所以 f1 比 f2 先執(zhí)行锭魔;
  • 在第二個(gè)例子中例证,由于 Future 函數(shù)體與 then 共用一個(gè)事件循環(huán),因此 f3 執(zhí)行后會(huì)立刻同步執(zhí)行 then 3迷捧;
  • 最后一個(gè)例子中织咧,F(xiàn)uture 函數(shù)體是 null,這意味著它不需要也沒(méi)有事件循環(huán)漠秋,因此后續(xù)的 then 也無(wú)法與它共享笙蒙。在這種場(chǎng)景下,Dart 會(huì)把后續(xù)的 then 放入微任務(wù)隊(duì)列庆锦,在下一次事件循環(huán)中執(zhí)行捅位。

通過(guò)一個(gè)綜合案例,來(lái)把之前介紹的各個(gè)執(zhí)行規(guī)則都串起來(lái)搂抒,再集中學(xué)習(xí)一下艇搀。
在下面的例子中,我們依次聲明了若干個(gè)異步任務(wù) Future求晶,以及微任務(wù)焰雕。在其中的一些 Future 內(nèi)部,我們又內(nèi)嵌了 Future 與 microtask 的聲明:


Future(() => print('f1'));//聲明一個(gè)匿名Future
Future fx = Future(() =>  null);//聲明Future fx芳杏,其執(zhí)行體為null

//聲明一個(gè)匿名Future矩屁,并注冊(cè)了兩個(gè)then。在第一個(gè)then回調(diào)里啟動(dòng)了一個(gè)微任務(wù)
Future(() => print('f2')).then((_) {
  print('f3');
  scheduleMicrotask(() => print('f4'));
}).then((_) => print('f5'));

//聲明了一個(gè)匿名Future爵赵,并注冊(cè)了兩個(gè)then吝秕。第一個(gè)then是一個(gè)Future
Future(() => print('f6'))
  .then((_) => Future(() => print('f7')))
  .then((_) => print('f8'));

//聲明了一個(gè)匿名Future
Future(() => print('f9'));

//往執(zhí)行體為null的fx注冊(cè)了了一個(gè)then
fx.then((_) => print('f10'));

//啟動(dòng)一個(gè)微任務(wù)
scheduleMicrotask(() => print('f11'));
print('f12');

先別急往下看結(jié)果,自己在小本本上寫寫空幻,或者自己敲代碼運(yùn)行一下

運(yùn)行一下郭膛,上述各個(gè)異步任務(wù)會(huì)依次打印其內(nèi)部執(zhí)行結(jié)果:


f12
f11
f1
f10
f2
f3
f5
f4
f6
f9
f7
f8

看到這兒,你可能已經(jīng)懵了氛悬。別急则剃,我們先來(lái)看一下這段代碼執(zhí)行過(guò)程中耘柱,Event Queue 與 Microtask Queue 中的變化情況,依次分析一下它們的執(zhí)行順序?yàn)槭裁磿?huì)是這樣的:

Event Queue 與 Microtask Queue 變化示例
  • 因?yàn)槠渌Z(yǔ)句都是異步任務(wù)棍现,所以先打印 f12调煎。
  • 剩下的異步任務(wù)中,微任務(wù)隊(duì)列優(yōu)先級(jí)最高己肮,因此隨后打印 f11士袄;然后按照 Future 聲明的先后順序,打印 f1谎僻。
  • 隨后到了 fx娄柳,由于 fx 的執(zhí)行體是 null,相當(dāng)于執(zhí)行完畢了艘绍,Dart 將 fx 的 then 放入微任務(wù)隊(duì)列赤拒,由于微任務(wù)隊(duì)列的優(yōu)先級(jí)最高,因此 fx 的 then 還是會(huì)最先執(zhí)行诱鞠,打印 f10挎挖。
  • 然后到了 fx 下面的 f2,打印 f2航夺,然后執(zhí)行 then蕉朵,打印 f3。f4 是一個(gè)微任務(wù)阳掐,要到下一個(gè)事件循環(huán)才執(zhí)行始衅,因此后續(xù)的 then 繼續(xù)同步執(zhí)行,打印 f5缭保。本次事件循環(huán)結(jié)束汛闸,下一個(gè)事件循環(huán)取出 f4 這個(gè)微任務(wù),打印 f4涮俄。
  • 然后到了 f2 下面的 f6蛉拙,打印 f6,然后執(zhí)行 then彻亲。這里需要注意的是孕锄,這個(gè) then 是一個(gè) Future 異步任務(wù),因此這個(gè) then苞尝,以及后續(xù)的 then 都被放入到事件隊(duì)列中了畸肆。后續(xù)的then 也被放到事件隊(duì)列 是因?yàn)?箭頭函數(shù) return了個(gè)future,所以后續(xù)的then是跟著他的宙址,如果沒(méi)有return future的話轴脐,then 會(huì)跟著前面的同步執(zhí)行
  • f6 下面還有 f9,打印 f9。
  • 最后一個(gè)事件循環(huán)大咱,打印 f7恬涧,以及后續(xù)的 f8。

你只需要記住一點(diǎn):then 會(huì)在 Future 函數(shù)體執(zhí)行完畢后立刻執(zhí)行碴巾,無(wú)論是共用同一個(gè)事件循環(huán)還是進(jìn)入下一個(gè)微任務(wù)溯捆。

在深入理解 Future 異步任務(wù)的執(zhí)行規(guī)則之后,我們?cè)賮?lái)看看怎么封裝一個(gè)異步函數(shù)厦瓢。

異步函數(shù)

對(duì)于一個(gè)異步函數(shù)來(lái)說(shuō)提揍,其返回時(shí)內(nèi)部執(zhí)行動(dòng)作并未結(jié)束,因此需要返回一個(gè) Future 對(duì)象煮仇,供調(diào)用者使用劳跃。調(diào)用者根據(jù) Future 對(duì)象,來(lái)決定:是在這個(gè) Future 對(duì)象上注冊(cè)一個(gè) then浙垫,等 Future 的執(zhí)行體結(jié)束了以后再進(jìn)行異步處理刨仑;還是一直同步等待 Future 執(zhí)行體結(jié)束。

對(duì)于異步函數(shù)返回的 Future 對(duì)象绞呈,如果調(diào)用者決定同步等待贸人,則需要在調(diào)用處使用 await 關(guān)鍵字间景,并且在調(diào)用處的函數(shù)體使用 async 關(guān)鍵字佃声。

在下面的例子中,異步方法延遲 3 秒返回了一個(gè) Hello 2019倘要,在調(diào)用處我們使用 await 進(jìn)行持續(xù)等待圾亏,等它返回了再打印:


//聲明了一個(gè)延遲3秒返回Hello的Future封拧,并注冊(cè)了一個(gè)then返回拼接后的Hello 2019
Future<String> fetchContent() => 
  Future<String>.delayed(Duration(seconds:3), () => "Hello")
    .then((x) => "$x 2019");

  main() async{
  String str = await fetchContent()
    print(str);//等待Hello 2019的返回
  }

也許你已經(jīng)注意到了志鹃,我們?cè)谑褂?await 進(jìn)行等待的時(shí)候,在等待語(yǔ)句的調(diào)用上下文函數(shù) main 加上了 async 關(guān)鍵字泽西。為什么要加這個(gè)關(guān)鍵字呢曹铃?

因?yàn)?Dart 中的 await 并不是阻塞等待,而是異步等待捧杉。Dart 會(huì)將調(diào)用體的函數(shù)也視作異步函數(shù)陕见,將等待語(yǔ)句的上下文放入 Event Queue 中,一旦有了結(jié)果味抖,Event Loop 就會(huì)把它從 Event Queue 中取出评甜,等待代碼繼續(xù)執(zhí)行。

我們先來(lái)看下這段代碼仔涩。第二行的 then 執(zhí)行體 f2 是一個(gè) Future忍坷,為了等它完成再進(jìn)行下一步操作,我們使用了 await,期望打印結(jié)果為 f1佩研、f2柑肴、f3、f4:


Future(() => print('f1'))
  .then((_) async => await Future(() => print('f2')))
  .then((_) => print('f3'));
Future(() => print('f4'));

實(shí)際上旬薯,當(dāng)你運(yùn)行這段代碼時(shí)就會(huì)發(fā)現(xiàn)嘉抒,打印出來(lái)的結(jié)果其實(shí)是 f1、f4袍暴、f2些侍、f3!

分析一下這段代碼的執(zhí)行順序:

  • 按照任務(wù)的聲明順序政模,f1 和 f4 被先后加入事件隊(duì)列岗宣。
  • f1 被取出并打印淋样;然后到了 then耗式。then 的執(zhí)行體是個(gè) future f2,于是放入 Event Queue趁猴。然后把 await 也放到 Event Queue 里刊咳。
  • 這個(gè)時(shí)候要注意了,Event Queue 里面還有一個(gè) f4儡司,我們的 await 并不能阻塞 f4 的執(zhí)行娱挨。因此,Event Loop 先取出 f4捕犬,打印 f4跷坝;然后才能取出并打印 f2,最后把等待的 await 取出碉碉,開(kāi)始執(zhí)行后面的 f3柴钻。

由于 await 是采用事件隊(duì)列的機(jī)制實(shí)現(xiàn)等待行為的,所以比它先在事件隊(duì)列中的 f4 并不會(huì)被它阻塞垢粮。

接下來(lái)贴届,我們?cè)倏戳硪粋€(gè)例子:在主函數(shù)調(diào)用一個(gè)異步函數(shù)去打印一段話,而在這個(gè)異步函數(shù)中蜡吧,我們使用 await 與 async 同步等待了另一個(gè)異步函數(shù)返回字符串:


//聲明了一個(gè)延遲2秒返回Hello的Future毫蚓,并注冊(cè)了一個(gè)then返回拼接后的Hello 2019
Future<String> fetchContent() => 
  Future<String>.delayed(Duration(seconds:2), () => "Hello")
    .then((x) => "$x 2019");
//異步函數(shù)會(huì)同步等待Hello 2019的返回,并打印
func() async => print(await fetchContent());

main() {
  print("func before");
  func();
  print("func after");
}

運(yùn)行這段代碼斩跌,我們發(fā)現(xiàn)最終輸出的順序其實(shí)是“func before”“func after”“Hello 2019”绍些。func 函數(shù)中的等待語(yǔ)句似乎沒(méi)起作用。這是為什么呢耀鸦?

我來(lái)給你分析一下這段代碼的執(zhí)行順序:

  • 首先柬批,第一句代碼是同步的啸澡,因此先打印“func before”。
  • 然后氮帐,進(jìn)入 func 函數(shù)嗅虏,func 函數(shù)調(diào)用了異步函數(shù) fetchContent,并使用 await 進(jìn)行等待上沐,因此我們把 fetchContent皮服、await 語(yǔ)句的上下文函數(shù) func 先后放入事件隊(duì)列。
  • await 的上下文函數(shù)并不包含調(diào)用棧参咙,因此 func 后續(xù)代碼繼續(xù)執(zhí)行龄广,打印“func after”。
  • 2 秒后蕴侧,fetchContent 異步任務(wù)返回“Hello 2019”择同,于是 func 的 await 也被取出,打印“Hello 2019”净宵。

通過(guò)上述分析敲才,你發(fā)現(xiàn)了什么現(xiàn)象?那就是 await 與 async 只對(duì)調(diào)用上下文的函數(shù)有效择葡,并不向上傳遞紧武。因此對(duì)于這個(gè)案例而言,func 是在異步等待敏储。如果我們想在 main 函數(shù)中也同步等待阻星,需要在調(diào)用異步函數(shù)時(shí)也加上 await,在 main 函數(shù)也加上 async虹曙。

各位大佬 應(yīng)該還是迷糊迫横,多看幾遍番舆,多敲幾遍 自然會(huì)懂得

總結(jié)

在 UI 編程過(guò)程中酝碳,異步和多線程是兩個(gè)相伴相生的名詞,也是很容易混淆的概念恨狈。對(duì)于異步方法調(diào)用而言疏哗,代碼不需要等待結(jié)果的返回,而是通過(guò)其他手段(比如通知禾怠、回調(diào)返奉、事件循環(huán)或多線程)在后續(xù)的某個(gè)時(shí)刻主動(dòng)(或被動(dòng))地接收?qǐng)?zhí)行結(jié)果。

因此吗氏,從辯證關(guān)系上來(lái)看芽偏,異步與多線程并不是一個(gè)同等關(guān)系:異步是目的,多線程只是我們實(shí)現(xiàn)異步的一個(gè)手段之一弦讽。而在 Flutter 中污尉,借助于 UI 框架提供的事件循環(huán)膀哲,我們可以不用阻塞的同時(shí)等待多個(gè)異步任務(wù),因此并不需要開(kāi)多線程被碗。我們一定要記住這一點(diǎn)某宪。

Q/A
  1. 假如有一個(gè)任務(wù)(讀寫文件或者網(wǎng)絡(luò))耗時(shí)10秒,并且加入到了事件任務(wù)隊(duì)列中锐朴,執(zhí)行單這個(gè)任務(wù)的時(shí)候不就把線程卡主嗎兴喂?

文件I/O和網(wǎng)絡(luò)調(diào)用并不是在Dart層做的,而是由操作系統(tǒng)提供的異步線程焚志,他倆把活兒干完之后把結(jié)果剛到隊(duì)列中衣迷,Dart代碼只是執(zhí)行一個(gè)簡(jiǎn)單的讀動(dòng)作。

  1. 單線程模型是指的事件隊(duì)列模型酱酬,和繪制界面的線程是一個(gè)嗎
    我們所說(shuō)的單線程指的是主Isolate蘑险。而GPU繪制指令有單獨(dú)的線程執(zhí)行,跟主Isolate無(wú)關(guān)岳悟。事實(shí)上Flutter提供了4種task runner佃迄,有獨(dú)立的線程去運(yùn)行專屬的任務(wù):
    1.Platform Task Runner:處理來(lái)自平臺(tái)(Android/iOS)的消息
    2.UI Task Runner:執(zhí)行渲染邏輯、處理native plugin的消息贵少、timer呵俏、microtask、異步I/O操作處理等
    3.GPU Task Runner:執(zhí)行GPU指令
    4.IO Task Runner:執(zhí)行I/O任務(wù)
    除此之外滔灶,操作系統(tǒng)本身也提供了大量異步并發(fā)機(jī)制普碎,可以利用多線程去執(zhí)行任務(wù)(比如socket),我們?cè)谥鱅solate中無(wú)需關(guān)心(如果真想主動(dòng)創(chuàng)建并發(fā)任務(wù)也可以)

// 第一段
  Future(() => print('f6'))
    .then((_) => Future(() => print('f7')))
    .then((_) => print('f8'));

執(zhí)行結(jié)果為:f6 f7 f8

 // 第二段
  Future(() => print('f6'))
  .then((_) {
      Future(() => print('f7'));
    })
  .then((_) => print('f8'));

執(zhí)行結(jié)果為:f6 f8 f7
上面這兩段代碼為什么執(zhí)行結(jié)果不一樣呢录平?

單行箭頭函數(shù)是Future麻车,和函數(shù)體里有Future不是一回事
then函數(shù)會(huì)返回future,所以用=>的寫法時(shí)斗这, 新創(chuàng)建的future會(huì)被then返回动猬,第二個(gè)then的調(diào)用者就是新的future對(duì)象, 所以第二個(gè)then就不跟著原先的future 而是跟著它的新future了表箭。
如果把=>換成大括號(hào)赁咙,此時(shí)第二個(gè)then還是跟著原先的future,和新future無(wú)關(guān)

  1. 下一個(gè)奇異的是什么時(shí)候

    2045年

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末免钻,一起剝皮案震驚了整個(gè)濱河市彼水,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌极舔,老刑警劉巖凤覆,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拆魏,居然都是意外死亡盯桦,警方通過(guò)查閱死者的電腦和手機(jī)澡绩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)俺附,“玉大人肥卡,你說(shuō)我怎么就攤上這事∈铝停” “怎么了步鉴?”我有些...
    開(kāi)封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)璃哟。 經(jīng)常有香客問(wèn)我氛琢,道長(zhǎng),這世上最難降的妖魔是什么随闪? 我笑而不...
    開(kāi)封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任阳似,我火速辦了婚禮,結(jié)果婚禮上铐伴,老公的妹妹穿的比我還像新娘撮奏。我一直安慰自己,他們只是感情好当宴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布畜吊。 她就那樣靜靜地躺著,像睡著了一般户矢。 火紅的嫁衣襯著肌膚如雪玲献。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天梯浪,我揣著相機(jī)與錄音捌年,去河邊找鬼。 笑死挂洛,一個(gè)胖子當(dāng)著我的面吹牛礼预,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抹锄,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逆瑞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了伙单?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哈肖,失蹤者是張志新(化名)和其女友劉穎吻育,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淤井,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年邓线,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肛著。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砾层,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贱案,到底是詐尸還是另有隱情肛炮,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布宝踪,位于F島的核電站侨糟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘩燥。R本人自食惡果不足惜秕重,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厉膀。 院中可真熱鬧溶耘,春花似錦、人聲如沸服鹅。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菱魔。三九已至留荔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澜倦,已是汗流浹背聚蝶。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藻治,地道東北人碘勉。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像桩卵,于是被迫代替她去往敵國(guó)和親验靡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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