函數(shù)式反應(yīng)型編程(FRP)

20170314201829186.png

前言

當(dāng)我們開始寫項(xiàng)目的時(shí)候,總會(huì)遇到一些情景凫碌,比如定時(shí)任務(wù)扑毡,ajax請(qǐng)求,要求我們?nèi)フ?qǐng)求大的文件或者圖片這些证鸥,然后我們就發(fā)現(xiàn)僚楞,直接寫代碼,會(huì)出現(xiàn)加載緩慢枉层,白屏這樣的問題泉褐,眾所周知,js是單線程的鸟蜡,所以js任務(wù)也是一個(gè)一個(gè)順序執(zhí)行的膜赃,就是同步執(zhí)行,后一個(gè)任務(wù)必須等待前一個(gè)任務(wù)完成之后才能執(zhí)行揉忘,就如前面所說的跳座,如果前一個(gè)任務(wù)花費(fèi)的時(shí)間很長端铛,就會(huì)造成阻塞,給用戶帶來不好的體驗(yàn)疲眷,我們要解決這些問題禾蚕,當(dāng)我們等待但是又不要阻塞程序,所以就需要異步處理這些耗時(shí)間的任務(wù)狂丝。

1.處理異步的方法

假設(shè)有多個(gè)異步任務(wù)换淆,且任務(wù)有依賴關(guān)系,后一個(gè)任務(wù)必須拿到前一個(gè)任務(wù)的執(zhí)行結(jié)果才可以執(zhí)行

作為剛剛?cè)腴T學(xué)習(xí)的小白几颜,比如我倍试,最先能想到的就是函數(shù)調(diào)用了

(1)回調(diào):容易造成回調(diào)地獄

回調(diào)是實(shí)現(xiàn)異步編程最簡單的方法,我們可以在一個(gè)函數(shù)中調(diào)用其他函數(shù)蛋哭,實(shí)現(xiàn)我們想要的邏輯

getData1(data1 => {
  getData2(data1, data2 => {
    getData3(data2, data3 => {
      getData4(data3, data4 => {
        getData5(data4, data5 => {
          // 終于取到data5了
        })
      })
    })
  })
})

乍一看县习,寫的還可以,也達(dá)到了預(yù)期的效果谆趾,就是看起來不美觀躁愿,而且還形成了回調(diào)地獄,但是如果里面出現(xiàn)很多問題棺妓,需要進(jìn)行異常處理及各種邏輯檢查呢攘已,那這一塊代碼就會(huì)變得非常長炮赦,非常復(fù)雜怜跑,可能下次同事看見了你的代碼,直接暴走吠勘。

為了讓代碼更具備可讀性性芬,Promise隆重登場。

(2)Promise:解決回調(diào)地獄

依舊來解決上面的問題

getData1(data1)
.then(data1 => {
   return getData2(data1);
})
.then(data2 => {
   return getData3(data2);
})
.then(data3 => {
   return getData4(data3);
})
.then(data4 => {
   return getData(data4);
})
.catch(err => {
    console.log(err);
})

我們直接一路鏈?zhǔn)秸{(diào)用剧防,看起來更清楚明了植锉,但是感覺這樣調(diào)用也不是個(gè)辦法。

你的上級(jí)詢問峭拘,那還能做的更優(yōu)雅嗎俊庇?這可難住了我,喔喔喔鸡挠,但是不要怕辉饱,es5的回調(diào)讓我陷入地獄,但是我爬起來了拣展,es6的Promise讓我得到夸獎(jiǎng)彭沼,es7這不是又出了好方法嗎?讓我們接下來看看es7的async/await吧备埃。

(3)async/await:簡化了邏輯姓惑,但是損失了異步帶來的性能優(yōu)勢(shì)(比如把并行變成串行,增加了時(shí)間開銷)

// 定義一個(gè)執(zhí)行Async函數(shù)方法
async function getSSQ () {
   let a = await getData1(data1)
   let b = await getData2(a)
   let c = await getData3(b)
   let d = await getData4(c)
   let e = await getData5(d)
   console.log(d);
}

確實(shí)好用褐奴,也可以使用try..catch了,啊,這你想肯定能滿足上級(jí)的要求了于毙,又簡單又優(yōu)雅敦冬,小白一眼就看懂,async/await帶著我走向了人生巔峰唯沮。

(4)各個(gè)方法優(yōu)缺點(diǎn)總結(jié)

方法 優(yōu)點(diǎn) 缺點(diǎn)
回調(diào) 簡單邏輯處理很方便 邏輯復(fù)雜時(shí)容易造成回調(diào)地獄
Promise 1.狀態(tài)改變就不會(huì)再變匪补,任何時(shí)候都能得到確切的結(jié)果 2.寫法符合思維邏輯 1.一旦創(chuàng)建,立即執(zhí)行烂翰,中途無法取消 2.處于pending狀態(tài)時(shí)夯缺,無法得知狀態(tài)3.不設(shè)置回調(diào)函數(shù),內(nèi)部錯(cuò)誤無法反映到外部
Async/await 1. 做到了串行的同步寫法 2.代碼清晰明了 1.做不到并行甘耿,除非await不在一個(gè)函數(shù)里面 2.沒有了promise的方法踊兜,比如race() 3.沒有Promise的reject方法,得寫在try...catch中

代碼非常簡潔易讀了佳恬,但是學(xué)海無涯捏境,我發(fā)現(xiàn)現(xiàn)在有了一個(gè)新的技術(shù),叫做FRP毁葱,看了一些文章垫言,文章里面一直說有了FRP,就使用流來處理異步倾剿,把異步數(shù)據(jù)看成數(shù)據(jù)流來處理筷频,會(huì)讓事情更簡單

那FRP到底是什么呢?

2.FRP是什么

首先讓我們先使用FRP直接實(shí)現(xiàn)上述的需求

 function getSSQ() {
        let data1 = 1;
        return rxjs.from(getData(data1)).pipe(
            rxjs.operators.mergeMap(a =>
                rxjs.from(getData(a))
            ),
            rxjs.operators.mergeMap(b =>
                rxjs.from(getData(b))
            ),
            rxjs.operators.mergeMap(c =>
                rxjs.from(getData(c))
            ),
            rxjs.operators.tap(console.log),
            rxjs.operators.mergeMap(d =>
                rxjs.from(getData(d))
            ),
            rxjs.operators.tap(e => {
            }),
        );
    }
    getSSQ().subscribe({
        // next(x) { console.log('got value ' + x); },
        // error(err) { console.error('something wrong occurred: ' + err); },
        complete() { console.log('done'); }
    })

看不懂吧前痘,看不懂沒關(guān)系凛捏,只需要知道from是建立流的,mergeMap()是操作流的芹缔,subscribe是訂閱流的坯癣,最后直接輸出結(jié)果就好了,我們先來了解一下什么是FRP及實(shí)際應(yīng)用最欠,重點(diǎn)是學(xué)習(xí)FRP不同的思維方式

(1)概念

FRP(Functional Reactive Programming),也叫函數(shù)式響應(yīng)式編程

函數(shù)反應(yīng)式編程 = 函數(shù)式編程(Functional programming)+響應(yīng)式編程(Reactive Programming)

如果不知道函數(shù)式編程的朋友示罗,推薦看這個(gè)編程指南,這邊主要講解響應(yīng)式編程

響應(yīng)式編程使用異步數(shù)據(jù)流編程芝硬,即將各種數(shù)據(jù)【包括http請(qǐng)求蚜点、DOM事件等】包裝成流的形式,用操作符對(duì)流進(jìn)行操作吵取,能用同步方式處理異步數(shù)據(jù)

光看這個(gè)概念禽额,我是完全沒法看明白的,所以需要拆開來看

(2)數(shù)據(jù)流是什么?

數(shù)據(jù)流是按時(shí)間排序的即將發(fā)生的事情的序列

image-20210824202121821.png

舉個(gè)例子脯倒,我們寫代碼時(shí)实辑,會(huì)對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換運(yùn)算,比如先轉(zhuǎn)成什么再轉(zhuǎn)成什么再轉(zhuǎn)成什么藻丢,轉(zhuǎn)換這整個(gè)過程相當(dāng)于一個(gè)流著數(shù)據(jù)的管道剪撬,數(shù)據(jù)以流的方式在這個(gè)管道中流通,這些數(shù)據(jù)轉(zhuǎn)換我們會(huì)使用各種方法悠反,相當(dāng)于傳入數(shù)據(jù)作為函數(shù)參數(shù)轉(zhuǎn)換后得到新數(shù)據(jù)結(jié)果残黑,最后的結(jié)果從管道中流出。

流轉(zhuǎn)換的思想為將數(shù)據(jù)事件抽象成管道中流通的流體斋否,轉(zhuǎn)換成新的數(shù)據(jù)事件梨水,這些事件還包含了基本的數(shù)據(jù)值,還可以進(jìn)行相應(yīng)的運(yùn)算茵臭,這種運(yùn)算讓我們不需要花時(shí)間去進(jìn)行事件監(jiān)聽什么的疫诽,我們只需要專注于數(shù)據(jù)的轉(zhuǎn)換,也就是事件的使用,而不是直接操作數(shù)據(jù)旦委。

所以我們?cè)趯W(xué)習(xí)這章內(nèi)容的時(shí)候奇徒,還應(yīng)該學(xué)會(huì)轉(zhuǎn)換思維。

總體思想:什么都可以是流缨硝,變量摩钙,用戶輸入,屬性查辩,高速緩存胖笛,數(shù)據(jù)結(jié)構(gòu)等,將時(shí)間線上的數(shù)據(jù)建模成流

(2)響應(yīng)式是什么宜肉?變化傳遞(跟著變化)

vue就是響應(yīng)式編程匀钧,我們只需要關(guān)注數(shù)據(jù)變化,不需要操作視圖改變谬返,因?yàn)橐晥D會(huì)跟著改變

(3)觀察者模式

是一種設(shè)計(jì)模式,允許定義一種訂閱機(jī)制日杈,可以在對(duì)象事件發(fā)生時(shí)通知多個(gè)觀察的該對(duì)象的其他對(duì)象

比如你花錢了之后銀行會(huì)給你發(fā)消息遣铝,就是觀察者模式,余額是被觀察的對(duì)象莉擒,用戶是觀察者

(4)迭代器模式

游標(biāo)模式酿炸,挨著挨著一步一步運(yùn)行

比如map,set,array都使用了迭代器模式

3.使用案例

前端的FRP的庫:Rxjs【比較多人使用】、Most涨冀,后續(xù)內(nèi)容使用Rxjs

Rxjs中文文檔:https://cn.rx.js.org/

Rxjs英文文檔:https://rxjs.dev/

讓我們學(xué)習(xí)幾個(gè)小案例填硕,來體會(huì)FRP的魅力吧~~

可引入也可以使用npm安裝:

<script src="https://cdn.bootcdn.net/ajax/libs/rxjs/7.3.0/rxjs.umd.js"></script>

RxJS 是一個(gè)庫,它通過使用 observable 序列來編寫異步和基于事件的程序。它提供了一個(gè)核心類型 Observable扁眯,附屬類型 (Observer壮莹、 Schedulers、 Subjects) 和操作符 (map姻檀、filter命满、reduce、every, 等等)绣版,這些數(shù)組操作符可以把異步事件作為集合來處理胶台。

基本概念:

  • Observable (可觀察對(duì)象): 表示一個(gè)概念,這個(gè)概念是一個(gè)可調(diào)用的未來值或事件的集合杂抽。

  • Observer (觀察者): 一個(gè)回調(diào)函數(shù)的集合诈唬,它知道如何去監(jiān)聽由 Observable 提供的值。

  • Subscription (訂閱): 表示 Observable 的執(zhí)行缩麸,主要用于取消 Observable 的執(zhí)行讯榕。

  • Operators (操作符): 采用函數(shù)式編程風(fēng)格的純函數(shù) (pure function),使用像 map匙睹、filter愚屁、concatflatMap 等這樣的操作符來處理集合痕檬。

  • Subject (主體): 相當(dāng)于 EventEmitter霎槐,并且是將值或事件多路推送給多個(gè) Observer 的唯一方式。

  • Schedulers (調(diào)度器): 用來控制并發(fā)并且是中央集權(quán)的調(diào)度員梦谜,允許我們?cè)诎l(fā)生計(jì)算時(shí)進(jìn)行協(xié)調(diào)丘跌,例如 setTimeoutrequestAnimationFrame 或其他。

借用官網(wǎng)第一個(gè)例子入門

注冊(cè)事件監(jiān)聽器的常規(guī)寫法如下

var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));

使用 RxJS 的話唁桩,創(chuàng)建一個(gè) observable 來代替闭树。

var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .subscribe(() => console.log('Clicked!'));

(1)實(shí)現(xiàn)計(jì)數(shù)器

a.以前實(shí)現(xiàn)計(jì)數(shù)器:

直接想實(shí)現(xiàn)方法,直接定義全局變量開始寫實(shí)現(xiàn)細(xì)節(jié),點(diǎn)擊則全局變量+1然后打印荒澡,這是我們平時(shí)思考的正常思維

let counter = 0;
buttton.on("click", ()=>{
   counter+=1;
   console.log(counter);
})

缺點(diǎn):

使用了全局變量:容易被改變值报辱,輸入輸出不確定性,后期維護(hù)困難等

b.有了FRP之后實(shí)現(xiàn)計(jì)數(shù)器:

  • 已知?jiǎng)?chuàng)建流的函數(shù)formEvent

  • 已知操作流的函數(shù):pipe单山、map碍现、scan、subscribe

    pipe:用于鏈接可觀察的運(yùn)算符

map:類似于Array.prototypr.map()米奸,它把每個(gè)源值傳遞給轉(zhuǎn)化函數(shù)以獲得相應(yīng)的輸出值昼接。

image-20210825103423821.png

scan:數(shù)組的 reduce 類似。它需要一個(gè)暴露給回調(diào)函數(shù)當(dāng)參數(shù)的初始值悴晰。每次回調(diào)函數(shù)運(yùn)行后的返回值會(huì)作為下次回調(diào)函數(shù)運(yùn)行時(shí)的參數(shù)

image-20210825104008290.png

subscribe:監(jiān)聽流慢睡,訂閱流

我們先在api中找到了對(duì)應(yīng)的方法,formEvent直接創(chuàng)建一個(gè)流->用pipe進(jìn)行數(shù)據(jù)流的連接(在里面可以寫事件的實(shí)現(xiàn)方法,我們只需要考慮怎么運(yùn)用事件處理漂辐,而不需要直接去操作數(shù)據(jù))->利用map進(jìn)行初始化操作->scan進(jìn)行數(shù)據(jù)相加操作->subscribe()方法訂閱整個(gè)流泪喊,最后輸出

rxjs.fromEvent(document.querySelector('.this'), 'click').pipe( // 連接運(yùn)算符
        rxjs.operators.map((_) => 1), // 將原值全變?yōu)?,不用定義全局變量
        rxjs.operators.scan((sum, val) => { // 相加
            return sum + val;
        }, 0)
    ).subscribe((x) => { console.log('got value ' + x); }); //打印

優(yōu)點(diǎn):

和直接操作數(shù)據(jù)相比者吁,除了創(chuàng)建流之外窘俺,F(xiàn)RP不需要有全局變量,直接可操作


(2)實(shí)現(xiàn)雙擊

例子:如果兩次click之間的間隔時(shí)間小于等于250ms复凳,為一次雙擊瘤泪,否則為兩次單擊,請(qǐng)?jiān)趩螕粲恕㈦p擊時(shí)分別log

以前實(shí)現(xiàn)雙擊:我們會(huì)考慮時(shí)間戳对途,判斷點(diǎn)擊事件的間隔時(shí)間是否小于等于250ms,然后進(jìn)行判斷髓棋,但是會(huì)出現(xiàn)問題实檀,如果連點(diǎn)三次,判斷上就會(huì)出現(xiàn)問題,或者設(shè)置標(biāo)志位按声,但是不管哪種方式實(shí)現(xiàn)膳犹,都會(huì)有些困難

<input type="button" onclick="aa()" ondblclick="bb()" value="點(diǎn)我">  
<script language="javascript">  
var isdb;  //設(shè)置變量
function aa(){  
    isdb=false;  //標(biāo)志位
    window.setTimeout(cc, 250) //這里調(diào)用window
    function cc(){  
        if(isdb!=false)return;  
        console.log("單擊")  
    }  
}  
function bb(){  
    isdb=true;  
    console.log("雙擊") 
}  

FRP實(shí)現(xiàn)雙擊:

  • 已知操作流的函數(shù):debounceTime、buffer签则、filter

debounceTime:去抖動(dòng)的作用须床,控制發(fā)送頻率操作

image-20210825110715526.png

buffer:將過往的值收集到一個(gè)數(shù)組中

image-20210825111010619.png

filter:類似于 Array.prototype.filter(), 它只會(huì)發(fā)出符合標(biāo)準(zhǔn)函數(shù)的值渐裂。

image-20210825111240904.png

雙擊事件也是操作api豺旬,有直接可以使用的去抖動(dòng)方法debounceTime(),思考流程應(yīng)該是點(diǎn)擊事件創(chuàng)建流->然后這個(gè)流去抖動(dòng)->收集去抖動(dòng)的值->判斷產(chǎn)生的每個(gè)數(shù)組長度,等于2就是雙擊柒凉,同理可得等于1就是單擊

 var button = document.querySelector('.this');
    var clickStream = rxjs.fromEvent(button, 'click'); //創(chuàng)建流

    var doubleClickStream = clickStream.pipe(
        rxjs.operators.buffer( // 收集點(diǎn)擊事件到數(shù)組中族阅,
            clickStream.pipe(
                rxjs.operators.debounceTime(250)
            )
        ),
        rxjs.operators.map(function (list) { return list.length; }),//返回?cái)?shù)組長度
        rxjs.operators.filter(function (x) { //過濾出雙擊
            return x === 2;
        })
    );
    //同理 單擊
    var singleClickStream = clickStream.pipe(
        rxjs.operators.buffer(
            clickStream.pipe(
                rxjs.operators.debounceTime(250)
            )
        ),
        rxjs.operators.map(function (list) { return list.length; }),
        rxjs.operators.filter(function (x) { return x === 1; })
    );
    // 顯示
    singleClickStream.subscribe(function (x) {
        document.querySelector('h2').textContent = 'click';
    });
    doubleClickStream.subscribe(function (x) {
        document.querySelector('h2').textContent = '' + x + 'x click';
    });

(3)實(shí)現(xiàn)拖動(dòng)

請(qǐng)使用mousedown、mousemove膝捞、mouseup事件來實(shí)現(xiàn)“鼠標(biāo)拖動(dòng)時(shí)坦刀,log:draging”

a.以前實(shí)現(xiàn):js實(shí)現(xiàn)拖拽,以前實(shí)現(xiàn)拖拽绑警,起碼是一兩百行代碼起步求泰,而且邏輯判斷上可能還會(huì)出現(xiàn)問題

b.現(xiàn)在FRP實(shí)現(xiàn):

  • 已知操作流的函數(shù):flatMap【現(xiàn)在已變成mergeMap】、takeUntil

    flatmap:每個(gè)流進(jìn)行運(yùn)算然后合并輸出

image-20210825114601621.png

takeUntil:先發(fā)出一個(gè)流的值计盒,直到第二個(gè)流發(fā)出值,就完成

image-20210825133659532.png

但是當(dāng)我們使用Rxjs實(shí)現(xiàn)的時(shí)候芽丹,代碼實(shí)現(xiàn)就會(huì)變得很少北启,只需要幾行就可以實(shí)現(xiàn)需求,如下所示【具體理解上可能會(huì)有些困難,學(xué)習(xí)具體的推薦從官方中文文檔入手咕村,比較詳細(xì)】

 let mousedown = rxjs.fromEvent(document, 'mousedown');
    let mousemove = rxjs.fromEvent(document, 'mousemove');
    let mouseup = rxjs.fromEvent(document, 'mouseup');

    mousedown.pipe(
        rxjs.operators.flatMap((_) => {
            return mousemove.pipe(rxjs.operators.takeUntil(mouseup))
        })
    ).subscribe(() => {
        console.log("draging");
    })

4.為什么要使用FRP

從處理異步的方法上场钉,我們發(fā)現(xiàn)async/await并不擅長處理并行需求,雖然也可以處理懈涛,但是耗費(fèi)時(shí)間多些逛万,但是FRP操作符,對(duì)于并行串行都可以很適用

流處理方式的價(jià)值且遠(yuǎn)不止于此批钠,對(duì)于事件處理也非常適用宇植,響應(yīng)式編程的思維方式也是非常有價(jià)值的一點(diǎn)

FRP的特性總結(jié)如下:

  • 純凈性 (Purity)

使得 RxJS 強(qiáng)大的正是它使用純函數(shù)來產(chǎn)生值的能力。這意味著你的代碼更不容易出錯(cuò)埋心。

通常你會(huì)創(chuàng)建一個(gè)非純函數(shù)指郁,在這個(gè)函數(shù)之外也使用了共享變量的代碼,這將使得你的應(yīng)用狀態(tài)一團(tuán)糟拷呆。

  • 流動(dòng)性 (Flow)

RxJS 提供了一整套操作符來幫助你控制事件如何流經(jīng) observables 闲坎。

5.總結(jié)

(1)優(yōu)點(diǎn)

  • 抽象層面更高

    FRP以流為單位,封裝了時(shí)間序列和具體的數(shù)據(jù)茬斧,隱藏了“狀態(tài)的同步”腰懂、“異步邏輯的具體實(shí)現(xiàn)”等底層細(xì)節(jié)。

  • 和函數(shù)式編程配合使用

    能夠使用組合项秉,像管道處理一樣處理各種流绣溜,符合函數(shù)式編程的思維。

  • 提供非阻塞伙狐、異步特性涮毫,便于處理異步情景,但是得是有非常復(fù)雜的異步情景時(shí)才適用贷屎,平時(shí)的簡單異步請(qǐng)求罢防,90%都是可以被async/await還有Promise解決的

  • 避免模式混用,回調(diào)和promise混用唉侄、全局變量和局部變量混用咒吐,最后可能成為無盡的callback+Promise地獄

  • 易于編寫維護(hù),及時(shí)響應(yīng)

響應(yīng)式編程可以加深你代碼抽象的程度属划,讓你可以更專注于定義與事件相互依賴的業(yè)務(wù)邏輯恬叹,而不是把大量精力放在實(shí)現(xiàn)細(xì)節(jié)上,同時(shí)同眯,使用響應(yīng)式編程還能讓你的代碼變得更加簡潔绽昼。

(2)缺點(diǎn)

  • 學(xué)習(xí)成本高,需要轉(zhuǎn)換思維须蜗,用流來思考

最后的最后借用尤大大的一句話

我個(gè)人傾向于在適合 Rx 的地方用 Rx硅确,但是不強(qiáng)求 Rx for everything目溉。比較合適的例子就是比如多個(gè)服務(wù)端實(shí)時(shí)消息流,通過 Rx 進(jìn)行高階處理菱农,最后到 view 層就是很清晰的一個(gè) Observable缭付,但是 view 層本身處理用戶事件依然可以沿用現(xiàn)有的范式。

FRP的思想和對(duì)事件操作的能力很不錯(cuò)循未,在需要使用的地方使用上會(huì)是錦上添花

6.參考文章

1.Rxjs思想入門

2.你一直都錯(cuò)過的反應(yīng)型編程

3.Rxjs光速入門

4.響應(yīng)式編程介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陷猫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子的妖,更是在濱河造成了極大的恐慌绣檬,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羔味,死亡現(xiàn)場離奇詭異河咽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赋元,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門忘蟹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人搁凸,你說我怎么就攤上這事媚值。” “怎么了护糖?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵褥芒,是天一觀的道長。 經(jī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
  • 文/蒼蘭香墨 我猛地睜開眼辆雾,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼肪笋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起度迂,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤藤乙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后惭墓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坛梁,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至草姻,卻和暖如春钓猬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撩独。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工敞曹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留账月,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓澳迫,卻偏偏與公主長得像局齿,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子橄登,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344