2019-09-23: 十一:Flutter之Dart異步操作?

十一:Flutter之Dart異步操作?

1: Dart 的異步模型?

我們先搞清楚dart是如何搞定異步操作的?

1.1: Dart 是單線程的

1.1.1: 程序中的耗時操作
開發(fā)中的耗時操作:
  • 在開發(fā)中辕羽、我們經(jīng)常會遇到一些耗時操作需要完成彻磁、比如網(wǎng)絡(luò)請求纬纪、文件讀取等等
  • 如果我們的主線程一直在等待這些耗時操作然爆、那么就會進行阻塞绎秒、無法響應(yīng)其他事件辕漂、比如用戶的點擊呢灶;
  • 顯然、我們不能這樣做钉嘹。
如何處理耗時的操作

針對如何處理耗時的操作鸯乃、不同的語言有不同的處理方式

  • 處理方式一:多線程、比如Java跋涣、C++缨睡、我們普遍使用的做法就是開啟另外一條新的線程(Thread)鸟悴、在新的線程中完成這些異步的操作、再通過線程間通信的方式宏蛉、將拿到的數(shù)據(jù)傳遞給主線程遣臼。
  • 處理方式二:單線程 + 事件循環(huán),比如JavaScript拾并、Dart就是基于單線程加事件循環(huán)來完成耗時操作的處理揍堰、不過單線程如何能進行耗時的操作。
1.1.2: 單線程的異步操作

之前很多開發(fā)者都對于單線程的異步操作很疑惑嗅义,其實它們并不沖突:

  • 因為我們的一個應(yīng)用程序大部分都是處于空閑的狀態(tài)屏歹、并不是無限制的在和用戶進行交互。
  • 比如等待用戶的點擊之碗、網(wǎng)絡(luò)請求數(shù)據(jù)的返回蝙眶、文件讀取的IO操作、這些等待的行為并不會阻塞我們的線程褪那。
  • 這是因為類似于網(wǎng)絡(luò)請求幽纷、文件讀取IO、我們都可以基于非阻塞式調(diào)用
阻塞式調(diào)用和非阻塞式的調(diào)用

如果想搞清楚這個點博敬、我們需要知道操作系統(tǒng)中的阻塞式調(diào)用和非阻塞式調(diào)用的概念友浸。

  • 阻塞式和非阻塞式關(guān)注的是程序在等待調(diào)用結(jié)果(消息、返回值)時的狀態(tài)偏窝。
  • 阻塞式調(diào)用:調(diào)用結(jié)果返回之前收恢、當(dāng)前線程會被掛起、調(diào)用線程只有在得到調(diào)用結(jié)果之后才會繼續(xù)執(zhí)行祭往。
  • 非阻塞式調(diào)用:調(diào)用執(zhí)行之后伦意、當(dāng)前線程不會停止執(zhí)行、只需要過一段時間來檢查一下有沒有結(jié)果返回即可硼补。

我們開發(fā)中很多的耗時操作驮肉、都可以基于這樣的非阻塞式調(diào)用。

  • 比如網(wǎng)絡(luò)請求本身使用socket通信已骇、而Socket本身提供了select模型离钝、可以進行非阻塞式的工作。
  • 比如文件讀取IO操作疾捍、我們可以使用操作系統(tǒng)提供的基于事件的回調(diào)機制奈辰。
    這些操作都不會阻塞我們單線程的繼續(xù)執(zhí)行、我們的線程在等待的過程中乱豆、可以繼續(xù)去做別的事情奖恰、等真正有了響應(yīng)、再去進行對應(yīng)的處理即可。

這時瑟啃、我們可能有兩個問題:

  • 問題1: 如果在多核CPU中论泛、單線程是不是就沒有充分利用CPU呢、這個問題后續(xù)補充說明蛹屿。
  • 問題2: 單線程是如何處理網(wǎng)絡(luò)通信屁奏、IO操作它們返回的結(jié)果呢、答案就是事件循環(huán)(Event Loop)错负。

1.2: Dart事件循環(huán)

1.2.1: 什么是事件循環(huán)

單線程模型中坟瓢、主要就是在維護著一個事件循環(huán)(Event Loop)

事件循環(huán)是什么呢?

  • 事實上事件循環(huán)就是將需要處理的一系列事件(包括點擊事件犹撒、IO事件折联、網(wǎng)絡(luò)事件)放在一個事件隊列中(Event Queue)中。
  • 不斷地從事件隊列(Event Queue)中取出事件识颊、并執(zhí)行其對應(yīng)需要執(zhí)行的代碼塊诚镰、直到事件隊列清空為止。

下面就是一段時間小循環(huán)的偽代碼如下:

// 事件循環(huán)的偽代碼

  List eventQueue = [];
  var event;

  while (true) {
    if (eventQueue.length > 0) {
      // 取出一個事件
      event = eventQueue.removeAt(0);
      // 執(zhí)行該事件
      event();
    }
  }

當(dāng)我們有一些事件祥款、比如點擊事件清笨、IO事件、網(wǎng)絡(luò)事件時刃跛、就會加入到EventLoop中抠艾、當(dāng)發(fā)現(xiàn)事件隊列中不為空時、就會立即取出事件奠伪、并且執(zhí)行事件跌帐。
齒輪??就是我們的事件循環(huán)首懈、它會從隊列中一次取出事件來執(zhí)行绊率。

1.2.2: 事件循環(huán)代碼的模擬

這里我們舉例一段Flutter的代碼:

RaisedButton (
    child: Text('click me'),
    onPressed: () {
      final myFeature = http.get('https://www.baidu.com');
      myFeature.then((response) {
        if (response.statusCode == 200) {
          print('Success!');
        }
      });
    },
  )
  • 一個按鈕RaisedButton、當(dāng)發(fā)生點擊時執(zhí)行onPressed函數(shù)究履。
  • onPressed函數(shù)中滤否、我們發(fā)送了一個網(wǎng)絡(luò)請求、請求成功后會執(zhí)行then中的函數(shù)最仑。
這些代碼是如何放在事件循環(huán)中執(zhí)行的呢藐俺?
  • 1: 當(dāng)用戶發(fā)生點擊的時候、onPressed回調(diào)函數(shù)被放入事件循環(huán)中執(zhí)行泥彤、執(zhí)行的過程中發(fā)送了一個網(wǎng)絡(luò)請求欲芹。
  • 2: 網(wǎng)絡(luò)請求發(fā)出去后、該事件循環(huán)不會被阻塞吟吝、而是發(fā)現(xiàn)要執(zhí)行的onPressed函數(shù)已經(jīng)結(jié)束菱父、會將它丟棄臣疑。
  • 3: 網(wǎng)絡(luò)請求成功后、會執(zhí)行then中傳入的回調(diào)函數(shù)扁远、這也是一個事件酬荞、該事件會被放入到事件循環(huán)中執(zhí)行、執(zhí)行完畢后粟瞬、事件循環(huán)將其丟棄同仆。
    盡管onPressed 和 then中的回調(diào)有一些差異、但是它們對于事件循環(huán)來說裙品、都是告訴它:我有一段代碼需要執(zhí)行俗批、快點幫我完成它。

2: Dart的異步操作

Dart 中的異步操作主要使用Future市怎、async扶镀、await
如果你之前接觸過前端的ES6、ES7焰轻、編程經(jīng)驗臭觉,那么完全可以將Feature理解成Promise、(async辱志、await)和ES7中基本一致蝠筑。

2.1: 認(rèn)識Feature

2.1.1: 同步的網(wǎng)絡(luò)請求

我們先來看一個例子吧:

  • 在這個例子中、我使用getNetworkData來模擬了一個網(wǎng)絡(luò)請求揩懒;
  • 該網(wǎng)絡(luò)請求在需要3秒鐘的時間什乙、之后返回數(shù)據(jù);
import 'dart:io';
main(List<String> args) {
/* 代碼執(zhí)行結(jié)果:
main function start
netWorkData
null
main function end
*/
  print('main function start');
  print(getNetWorkData());
  print('main function end');
}

String getNetWorkData() {
  sleep(Duration(seconds: 3));
  print('netWorkData');
}

上面代碼執(zhí)行結(jié)果:

main function start
/// 等待3秒
netWorkData
null
main function end

顯然已球、上面的代碼不是我們想要的執(zhí)行效果臣镣、因為網(wǎng)絡(luò)請求阻塞了main函數(shù)、那么意味著其后所有的代碼都無法正常的繼續(xù)執(zhí)行智亮。

2.1.2: 異步的網(wǎng)絡(luò)請求

我們對上面的同步執(zhí)行代碼進行改進

  • 和剛才的代碼唯一的區(qū)別在于我使用Future對象來將耗時操作放在了其中傳入的函數(shù)中忆某;
  • 稍后、我們會說明它具體的一些API阔蛉、我們就暫時知道我創(chuàng)建了一個Future對象實例即可弃舒。
import 'dart:io';
main(List<String> args) {
  print('main function start');

  // 使用變量來接收getNetWorkData返回的future對象
  var future = getNetWorkData();

  // 當(dāng)future實例有返回結(jié)果時、會自動回調(diào)then中傳入的函數(shù)
  // 該函數(shù)會放入到事件循環(huán)中状原、被執(zhí)行聋呢。
  future.then((value) {
    // 獲取返回成功的回調(diào)
    /// value=newWorkData
    print('value---------------$value');
  }).catchError((error) {
    // 捕獲出現(xiàn)的異常error
    print('error---------$error');
  });
  print('future----------------$future');
  print(getNetWorkData());
  print('main function end');

  /* 第1次打印結(jié)果:
  main function start
  Instance of 'Future<String>'
  main function end
  */


  // 第2次success打印結(jié)果:
  /*
  main function start
  future----------------Instance of 'Future<String>'
  Instance of 'Future<String>'
  main function end
  value---------------newWorkData
  */

  // 第3次failure打印結(jié)果:
  /*
  main function start
  future----------------Instance of 'Future<String>'
  Instance of 'Future<String>'
  main function end
  error---------Exception: 網(wǎng)絡(luò)請求出錯
  Unhandled exception:
  Exception: 網(wǎng)絡(luò)請求出錯
  #0      getNetWorkData.<anonymous closure> (file:///Users/qxu7859/Desktop/Dart%E7%BB%83%E4%B9%A0/7_Dart_%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C.dart:99:5)
  #1      new Future.<anonymous closure> (dart:async/future.dart:176:37)
  #2      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:21:15)
  #3      _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
  #4      _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
  #5      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)

  */
}

Future<String> getNetWorkData() {
  return Future<String>(() {
    sleep(Duration(seconds: 3));
    /// 返回成功結(jié)果
    //return 'newWorkData';

    /// 返回異常
    throw Exception('網(wǎng)絡(luò)請求出錯');
  });
}

2.1.3: Future使用補充

補充1: 上面案例的總結(jié):

我們通過一個案例來學(xué)習(xí)一個future的使用過程:

  • 1: 創(chuàng)建一個Future對象(可能是我們創(chuàng)建的、也可能是調(diào)用內(nèi)部API或者第三方API獲取到的一個Future)颠区、總之你需要獲取一個Future實例削锰。
  • 2: 通過.then成功回調(diào)函數(shù)的方式來監(jiān)聽Future內(nèi)部執(zhí)行完成時獲取的結(jié)果
  • 3: 通過.catchError(失敗或異常回調(diào)函數(shù)的方式來監(jiān)聽Future內(nèi)部執(zhí)行失敗或者出現(xiàn)異常時的錯誤信息)
補充2: Future的兩種狀態(tài)

事實上Future在執(zhí)行的整個過程中毕莱、我們通常把它分成兩種狀態(tài):未完成狀態(tài) 和 完成狀態(tài)

狀態(tài)一:未完成狀態(tài)(unCompleted)
  • 執(zhí)行Future內(nèi)部的操作時(在上面的案例中就是具體的網(wǎng)絡(luò)請求過程器贩、我們使用了延遲來模擬)测暗,我們稱這個過程為未完成狀態(tài)。
狀態(tài)二:完成狀態(tài)(completed)
  • 當(dāng)Future內(nèi)部的操作執(zhí)行完成磨澡、通常會返回一個值碗啄、或者拋出一個異常
  • 這兩種情況、我們都稱為Future為完成狀態(tài)
    Dart官網(wǎng)有這兩種狀態(tài)解析稳摄、之所以貼出來時區(qū)別于Promise的三種狀態(tài)
補充三:Future的鏈?zhǔn)秸{(diào)用

上面代碼我們可以進行如下改進

  • 我們可以在then中繼續(xù)返回值稚字、會在下一個鏈?zhǔn)降膖hen調(diào)用回調(diào)函數(shù)中拿到返回的結(jié)果。
import 'dart:io';

Future<String> getNetWorkData() {
  return Future<String>(() {
    sleep(Duration(seconds: 3));
    /// 返回成功結(jié)果
    return 'newWorkData';

    /// 返回異常
    //throw Exception('網(wǎng)絡(luò)請求出錯');
  });
}

main(List<String> args) {

  // 打印結(jié)果:
  /*
  main function start
  main function end
  value1=newWorkData
  value2=content data2
  value3=content-data3

  */

  print('main function start');

  getNetWorkData().then((value1) {
    print('value1=$value1');
    return 'content data2';
  }).then((value2) {
    print('value2=$value2');
    return 'content-data3';
  }).then((value3) {
    print('value3=$value3');
  });

  print('main function end');
}

補充4: Future其他API
4.1: Future.value(value)
  • 直接獲取一個完整的Future厦酬、該Future會直接調(diào)用then的回調(diào)函數(shù)胆描。
import 'dart:io';

  main(List<String> args) {

    /** 
    main function start
    main function end
    value=我是Future對象獲取者 
    */

  print('main function start');

  Future.value('我是Future對象獲取者').then((value) {
    print('value=$value');
  });

  print('main function end');
}

為什么會立即執(zhí)行、但是value=我是Future對象獲取者是最后打印的呢仗阅?

  • 這是因為Future中的then會作為新的任務(wù)添加到事件隊列中(event Queue)昌讲、加入之后你肯定需要排隊執(zhí)行了。
4.2: Future.error(object)
  • 直接獲取一個完成的Future减噪、但是是一個發(fā)生異常的Future短绸、該Future會直接調(diào)用catchError的回調(diào)函數(shù)。
/* 打印結(jié)果:
  main function start
  main function end
  error=Exception: 錯誤信息
  */
  print('main function start');
  Future.error(Exception('錯誤信息')).catchError((error) {
    print('error=${error}');
  });
  print('main function end');
4.3: Future.delayed(時間筹裕、回調(diào)函數(shù))
  • 在延遲一定時間時執(zhí)行回調(diào)函數(shù)醋闭、執(zhí)行完回調(diào)函數(shù)會執(zhí)行then的回調(diào)。
  • 之前的案例朝卒、我們也可以使用它來模擬证逻、但是直接學(xué)習(xí)這個API會有點疑惑:
/*
main function start
main function end
value=3秒后的信息
*/
  print('main function start');

  Future.delayed(Duration(seconds: 3), () {
    return '3秒后的信息';
  }).then((value) {
    print('value=$value');
  });

  print('main function end');

2.2: await、async

2.2.1: 理論概念理解

如果你已經(jīng)完全搞懂了Future抗斤、那么學(xué)習(xí)await囚企、async應(yīng)該沒啥難度。
await瑞眼、async是什么呢龙宏?

  • 它們是Dart中的關(guān)鍵字。
  • 它們可以讓我們用同步的代碼去實現(xiàn)異步的操作负拟。
  • 并且烦衣、通常一個async的函數(shù)會返回一個Future歹河、
    我們已經(jīng)知道掩浙、Future可以做到不阻塞我們的線程、讓線程繼續(xù)執(zhí)行秸歧、并且在完成某個操作時改變自己的狀態(tài)厨姚、并且回調(diào)then或者catchError回調(diào)。
如何生成一個Future呢键菱?
  • 1: 通過我們前面學(xué)習(xí)的Future構(gòu)造函數(shù)谬墙、或者后面學(xué)習(xí)的Future其他API都可以今布。
  • 還有一種就是通過async的函數(shù)。

2.2.2: 案例代碼

  • 因為Future.delayed返回的是一個Future對象拭抬、我們不能把它看作成同步的返回結(jié)果: ’netWork data‘去使用
  • 也就是我們不能把這個異步的代碼相當(dāng)于同步一樣去使用
main(List<String> args) {
  print('main function start');

  print(getNetWorkData);

  print('main function end');
}

String getNetWorkData() {
  var result = Future.delayed(Duration(seconds: 3), () {
    return 'netWork data';
  });

  return '請求的數(shù)據(jù): ' + result;
}
>>>顯示報錯:result 是一個Future對象部默、沒辦法跟String拼接。

現(xiàn)在我們使用await修改下面的代碼:

  • 我在Future.delayed函數(shù)前加了一個await
  • 一旦有了這個關(guān)鍵字造虎、那么這個操作就會等待Future.delayed執(zhí)行完畢傅蹂、并且等待它的結(jié)果。
main(List<String> args) {
  print('main function start');

  print(getNetWorkData());

  print('main function end');
  
}

String getNetWorkData() {
  var result = await Future.delayed(Duration(seconds: 3), () {
    return 'network data';
  });

  return '請求的數(shù)據(jù)' + result;
}

報錯信息如下:await 關(guān)鍵字只能使用在async函數(shù)中

修改后你會發(fā)現(xiàn)報錯:

  • await關(guān)鍵字只能使用在async函數(shù)中算凿。
  • 所以我們需要將getNetWorkData函數(shù)定義成async函數(shù)份蝴。

接續(xù)修改上述代碼:

  • 在方法后面加入一個關(guān)鍵字 async
  • 同時將返回對象寫成如Future<String>
main(List<String> args) {
  print('main function start');

  print(getNetWorkData());
  getNetWorkData().then((value) {
    print('value=$value');
  });
  print('main function end');
}

/// Error: Functions marked 'async' must have a return type assignable to 'Future'
Future<String> getNetWorkData() async {
  var result = await Future.delayed(Duration(seconds: 3), () {
    return 'network data';
  });

  return '請求的數(shù)據(jù)' + result;
}

打印結(jié)果:
main function start
Instance of 'Future<String>'
main function end
value=請求的數(shù)據(jù)network data
上述代碼就是我們理想中執(zhí)行的代碼了
  • 我們現(xiàn)在可以像同步代碼一樣去使用Future異步返回的結(jié)果了。
  • 等待拿到結(jié)果之后和其他數(shù)據(jù)進行拼接氓轰、然后一起返回婚夫。
  • 返回的時候并不需要包裝一個Future、直接返回即可署鸡、但是返回的時候返回值會默認(rèn)包裝在一個Future中案糙。

2.3: 讀取json案例

后續(xù)結(jié)合Flutter講解.........

3: Dart的異步補充

3.1: 任務(wù)執(zhí)行順序

3.1.1: 認(rèn)識微任務(wù)隊列

在前面練習(xí)中、我們知道Dart中有一個事件循環(huán)(Event Loop)來執(zhí)行我們的代碼靴庆、里面存在一個事件隊列(Event Queue)侍筛、事件循環(huán)不斷從事件隊列中取出事件執(zhí)行。
但是如果嚴(yán)格來劃分的話撒穷、在Dart中還存在另一個隊列:微任務(wù)隊列(Microtask Queue)匣椰。

  • 微任務(wù)隊列的優(yōu)先級要高于事件隊列;
  • 也就是說端礼、事件循環(huán)都是優(yōu)先執(zhí)行微任務(wù)隊列中的任務(wù)禽笑、在執(zhí)行事件隊列中的任務(wù)。
    那么在Flutter開發(fā)中蛤奥、哪些是放在事件隊列中佳镜、哪些是放在微任務(wù)隊列中呢。
  • 所有的外部事件任務(wù)都是在事件隊列中凡桥、如IO蟀伸、計時器、點擊缅刽、以及繪制事件等啊掏。
  • 而微任務(wù)通常來源于Dart內(nèi)部、并且微任務(wù)非常少衰猛、這是因為如果微任務(wù)非常多迟蜜、那會造成事件隊列排不上隊、會阻塞任務(wù)隊列的執(zhí)行(比如用戶點擊沒有反應(yīng)的情況)啡省。
    說到這里娜睛、你可能凌亂了髓霞、在Dart中單線程中、代碼到底是怎樣執(zhí)行的呢畦戒?
  • 1: Dart的入口是main函數(shù)方库、所以main函數(shù)中的代碼會優(yōu)先執(zhí)行。
  • 2: main函數(shù)執(zhí)行完畢后障斋、會啟動一個事件循環(huán)(Event Loop)就會啟動薪捍、啟動后開始執(zhí)行隊列中的任務(wù);
  • 3: 首先配喳、會按照先進先出的順序酪穿、執(zhí)行微任務(wù)隊列(Microtask Queue)中的所有任務(wù);
  • 4: 其次晴裹、會按照先進先出的順序被济、執(zhí)行事件隊列(Event Queue)中的所有任務(wù);


    圖片.png
3.1.2: 如何創(chuàng)建微任務(wù)

在開發(fā)中涧团、我們可以通過Dart中async下的scheduleMicrotask來創(chuàng)建一個微任務(wù)

// 通過await來修改上述代碼
main(List<String> args) {
  print('main function start');

  print(getNetWorkData());
  getNetWorkData().then((value) {
    print('value=$value');
  });

  print('main function end');


  scheduleMicrotask(() {
    print('我是scheduleMicrotask創(chuàng)建的微任務(wù)');
  });
 
打印結(jié)果:
main function start
Instance of 'Future<String>'
main function end
我是scheduleMicrotask創(chuàng)建的微任務(wù)
value=請求的數(shù)據(jù)network data
}

在開發(fā)中只磷、如果我們有一個任務(wù)不希望它放在EventQueue中依此排隊、那么就可以創(chuàng)建一個微任務(wù)泌绣。

Future 的代碼是加入到事件隊列只是微任務(wù)隊列呢钮追?

Future中通常有兩個函數(shù)執(zhí)行體:

  • Future 構(gòu)造函數(shù)傳入的函數(shù)體
  • then的函數(shù)體(catchError等同看待)

那么它們是加入到什么隊列中的呢?

  • Future 構(gòu)造函數(shù)傳入的函數(shù)體放在事件隊列中
  • then的函數(shù)體要分成三種情況:
  • 情況下1: Future 沒有執(zhí)行完成(有任務(wù)需要執(zhí)行)阿迈,那么then會直接被添加到Future的函數(shù)執(zhí)行體后元媚;
  • 情況2: 如果Future執(zhí)行完成后就then、該then的函數(shù)體被放到微任務(wù)隊列中苗沧。當(dāng)前Future執(zhí)行完成后執(zhí)行微任務(wù)隊列刊棕;
  • 情況3: 如果Future是鏈?zhǔn)秸{(diào)用、意味著then未執(zhí)行完待逞、下一個then不會執(zhí)行甥角;

情況1的代碼案例:

// 打印:
  // future_1
  // then_1
  // future_1加入到eventqueue中识樱、緊隨其后then_1加入到eventqueue中
  Future(() => print('future_1')).then((_) => print('then_1'));

情況2的代碼案例:

// 打印then_2
  // Future沒有函數(shù)執(zhí)行體(相當(dāng)于Future執(zhí)行完就then)嗤无、then_2被加入到微任務(wù)microtaskqueue中
  Future(() => null).then((_) => print('then_2'));

情況3的代碼案例:

/* 打印
  future_3
  then_3
  ehtn_4
  */
  // future_3 、then_3怜庸、then_4依此被加入到eventqueue中
  Future(() => print('future_3')).then((_) => print('then_3')).then((_) => print('ehtn_4'));
 
3.1.3: 代碼執(zhí)行順序

我們根據(jù)前面的解讀來測試一下終極的代碼執(zhí)行順序案例:


main(List<String> args) {
  print('main function start');
  //
  Future(() => print('task1'));
  //
  
  //
  Future(() => print('task2')).then((_) {
    print('task3');
    scheduleMicrotask(() => print('task4'));
  }).then((_) => print('task5'));
  
  //
  final future = Future(() => null);
  future.then((_) => print('task6'));
  
  //
  scheduleMicrotask(() => print('task7'));
  //
  Future(() => print('task8'))
  .then((_) => Future(() => print('task9')))
  .then((_) => print('task10'));
  //
  print('main function end')
;}

/* 打印結(jié)果
main function start
main function end
task7
task1
task6
task2
task3
task5
task4
task8
task9
task10
*/

3.2: 多核CPU的利用

......

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末当犯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子休雌,更是在濱河造成了極大的恐慌灶壶,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杈曲,死亡現(xiàn)場離奇詭異驰凛,居然都是意外死亡,警方通過查閱死者的電腦和手機担扑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門恰响,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人涌献,你說我怎么就攤上這事胚宦。” “怎么了燕垃?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵枢劝,是天一觀的道長。 經(jīng)常有香客問我卜壕,道長您旁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任轴捎,我火速辦了婚禮鹤盒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘侦副。我一直安慰自己侦锯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布秦驯。 她就那樣靜靜地躺著尺碰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪译隘。 梳的紋絲不亂的頭發(fā)上葱蝗,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音细燎,去河邊找鬼两曼。 笑死,一個胖子當(dāng)著我的面吹牛玻驻,可吹牛的內(nèi)容都是我干的悼凑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼璧瞬,長吁一口氣:“原來是場噩夢啊……” “哼户辫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗤锉,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤渔欢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘟忱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奥额,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡苫幢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垫挨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韩肝。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖九榔,靈堂內(nèi)的尸體忽然破棺而出哀峻,到底是詐尸還是另有隱情,我是刑警寧澤哲泊,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布剩蟀,位于F島的核電站,受9級特大地震影響切威,放射性物質(zhì)發(fā)生泄漏育特。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一牢屋、第九天 我趴在偏房一處隱蔽的房頂上張望且预。 院中可真熱鬧,春花似錦烙无、人聲如沸锋谐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涮拗。三九已至,卻和暖如春迂苛,著一層夾襖步出監(jiān)牢的瞬間三热,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工三幻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留就漾,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓念搬,卻偏偏與公主長得像抑堡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朗徊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

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