詳解generator函數(shù)

轉(zhuǎn)載自:https://www.cnblogs.com/rogerwu/p/10764046.html

一、什么是 Generator 函數(shù)

在Javascript中鳄橘,一個(gè)函數(shù)一旦開始執(zhí)行,就會(huì)運(yùn)行到最后或遇到return時(shí)結(jié)束袍榆,運(yùn)行期間不會(huì)有其它代碼能夠打斷它朴恳,也不能從外部再傳入值到函數(shù)體內(nèi)

而Generator函數(shù)(生成器)的出現(xiàn)使得打破函數(shù)的完整運(yùn)行成為了可能,其語法行為與傳統(tǒng)函數(shù)完全不同

Generator函數(shù)是ES6提供的一種異步編程解決方案,形式上也是一個(gè)普通函數(shù)餐曹,但有幾個(gè)顯著的特征:

  • function關(guān)鍵字與函數(shù)名之間有一個(gè)星號(hào) "*" (推薦緊挨著function關(guān)鍵字)
  • 函數(shù)體內(nèi)使用 yield 表達(dá)式,定義不同的內(nèi)部狀態(tài) (可以有多個(gè)yield)
  • 直接調(diào)用 Generator函數(shù)并不會(huì)執(zhí)行敌厘,也不會(huì)返回運(yùn)行結(jié)果台猴,而是返回一個(gè)遍歷器對(duì)象(Iterator Object)
  • 依次調(diào)用遍歷器對(duì)象的next方法,遍歷 Generator函數(shù)內(nèi)部的每一個(gè)狀態(tài)
{
  // 傳統(tǒng)函數(shù)
  function foo() {
    return 'hello world'
  }

  foo()   // 'hello world'俱两,一旦調(diào)用立即執(zhí)行


  // Generator函數(shù)
  function* generator() {
    yield 'status one'         // yield 表達(dá)式是暫停執(zhí)行的標(biāo)記  
    return 'hello world'
  }

  let iterator = generator()   // 調(diào)用 Generator函數(shù)饱狂,函數(shù)并沒有執(zhí)行,返回的是一個(gè)Iterator對(duì)象
  iterator.next()              // {value: "status one", done: false}宪彩,value 表示返回值休讳,done 表示遍歷還沒有結(jié)束
  iterator.next()              // {value: "hello world", done: true},value 表示返回值尿孔,done 表示遍歷結(jié)束
}

上面的代碼中可以看到傳統(tǒng)函數(shù)和Generator函數(shù)的運(yùn)行是完全不同的俊柔,傳統(tǒng)函數(shù)調(diào)用后立即執(zhí)行并輸出了返回值筹麸;Generator函數(shù)則沒有執(zhí)行而是返回一個(gè)Iterator對(duì)象,并通過調(diào)用Iterator對(duì)象的next方法來遍歷雏婶,函數(shù)體內(nèi)的執(zhí)行看起來更像是“被人踢一腳才動(dòng)一下”的感覺

{
  function* gen() {
    yield 'hello'
    yield 'world'
    return 'ending'
  }

  let it = gen()

  it.next()   // {value: "hello", done: false}
  it.next()   // {value: "world", done: false}
  it.next()   // {value: "ending", done: true}
  it.next()   // {value: undefined, done: true}
}

上面代碼中定義了一個(gè) Generator函數(shù)物赶,其中包含兩個(gè) yield 表達(dá)式和一個(gè) return 語句(即產(chǎn)生了三個(gè)狀態(tài))

每次調(diào)用Iterator對(duì)象的next方法時(shí),內(nèi)部的指針就會(huì)從函數(shù)的頭部或上一次停下來的地方開始執(zhí)行留晚,直到遇到下一個(gè) yield 表達(dá)式或return語句暫停酵紫。換句話說,Generator 函數(shù)是分段執(zhí)行的错维,yield表達(dá)式是暫停執(zhí)行的標(biāo)記奖地,而 next方法可以恢復(fù)執(zhí)行

執(zhí)行過程如下:

  1. 第一次調(diào)用next方法時(shí),內(nèi)部指針從函數(shù)頭部開始執(zhí)行需五,遇到第一個(gè) yield 表達(dá)式暫停鹉动,并返回當(dāng)前狀態(tài)的值 'hello'
  2. 第二次調(diào)用next方法時(shí),內(nèi)部指針從上一個(gè)(即第一個(gè)) yield 表達(dá)式開始宏邮,遇到第二個(gè) yield 表達(dá)式暫停泽示,返回當(dāng)前狀態(tài)的值 'world'
  3. 第三次調(diào)用next方法時(shí),內(nèi)部指針從第二個(gè) yield 表達(dá)式開始蜜氨,遇到return語句暫停械筛,返回當(dāng)前狀態(tài)的值 'ending',同時(shí)所有狀態(tài)遍歷完畢飒炎,done 屬性的值變?yōu)閠rue
  4. 第四次調(diào)用next方法時(shí)埋哟,由于函數(shù)已經(jīng)遍歷運(yùn)行完畢,不再有其它狀態(tài)郎汪,因此返回 {value: undefined, done: true}赤赊。如果繼續(xù)調(diào)用next方法,返回的也都是這個(gè)值


    997093-20190425144610438-1431969206.png

二煞赢、yield 表達(dá)式

  • yield 表達(dá)式只能用在 Generator 函數(shù)里面抛计,用在其它地方都會(huì)報(bào)錯(cuò)

    {
      (function (){
        yield 1;
      })()
    
      // SyntaxError: Unexpected number
      // 在一個(gè)普通函數(shù)中使用yield表達(dá)式,結(jié)果產(chǎn)生一個(gè)句法錯(cuò)誤
    }
    
  • yield 表達(dá)式如果用在另一個(gè)表達(dá)式中照筑,必須放在圓括號(hào)里面

    {
      function* demo() {
        console.log('Hello' + yield); // SyntaxError
        console.log('Hello' + yield 123); // SyntaxError
      
        console.log('Hello' + (yield)); // OK
        console.log('Hello' + (yield 123)); // OK
      }
    }
    
  • yield 表達(dá)式用作參數(shù)或放在賦值表達(dá)式的右邊吹截,可以不加括號(hào)

    {
      function* demo() {
        foo(yield 'a', yield 'b'); // OK
        let input = yield; // OK
      }
    }
    
  • yield 表達(dá)式和return語句的區(qū)別

    相似:都能返回緊跟在語句后面的那個(gè)表達(dá)式的值

    區(qū)別:

    • 每次遇到 yield,函數(shù)就暫停執(zhí)行凝危,下一次再從該位置繼續(xù)向后執(zhí)行波俄;而 return 語句不具備記憶位置的功能
    • 一個(gè)函數(shù)只能執(zhí)行一次 return 語句,而在 Generator 函數(shù)中可以有任意多個(gè) yield

三蛾默、yield* 表達(dá)式

如果在 Generator 函數(shù)里面調(diào)用另一個(gè) Generator 函數(shù)懦铺,默認(rèn)情況下是沒有效果的
{
  function* foo() {
    yield 'aaa'
    yield 'bbb'
  }

  function* bar() {
    foo()
    yield 'ccc'
    yield 'ddd'
  }

  let iterator = bar()

  for(let value of iterator) {
    console.log(value)
  }

  // ccc
  // ddd

}

上例中,使用 for...of 來遍歷函數(shù)bar的生成的遍歷器對(duì)象時(shí)支鸡,只返回了bar自身的兩個(gè)狀態(tài)值阀趴。此時(shí)昏翰,如果想要正確的在bar 里調(diào)用foo,就需要用到 yield* 表達(dá)式

yield 表達(dá)式用來在一個(gè) Generator 函數(shù)里面 執(zhí)行 另一個(gè) Generator 函數(shù)*

{
  function* foo() {
    yield 'aaa'
    yield 'bbb'
  }

  function* bar() {
    yield* foo()      // 在bar函數(shù)中 **執(zhí)行** foo函數(shù)
    yield 'ccc'
    yield 'ddd'
  }

  let iterator = bar()

  for(let value of iterator) {
    console.log(value)
  }

  // aaa
  // bbb
  // ccc
  // ddd
}

四刘急、next() 方法的參數(shù)

yield表達(dá)式本身沒有返回值棚菊,或者說總是返回undefined。next方法可以帶一個(gè)參數(shù)叔汁,該參數(shù)就會(huì)被當(dāng)作上一個(gè)yield表達(dá)式的返回值

  [rv] = yield [expression]

  expression:定義通過遍歷器從生成器函數(shù)返回的值统求,如果省略,則返回 undefined
  rv:接收從下一個(gè) next() 方法傳遞來的參數(shù)

先看一個(gè)簡單的小栗子据块,并嘗試解析遍歷生成器函數(shù)的執(zhí)行過程

{
  function* gen() {
    let result = yield 3 + 5 + 6
    console.log(result)
    yield result
  }

  let it = gen()
  console.log(it.next())      // {value: 14, done: false}
  console.log(it.next())      // undefined    {value: undefined, done: false}
}

(此處分析過程純屬個(gè)人理解码邻,有誤之處,歡迎批評(píng)指正A砑佟)

第一次調(diào)用遍歷器對(duì)象的next方法像屋,函數(shù)從頭部開始執(zhí)行,遇到第一個(gè) yield 暫停边篮,在這個(gè)過程中其實(shí)是分了三步:

(1)己莺、聲明了一個(gè)變量result,并將聲明提前戈轿,默認(rèn)值為 undefined

(2)凌受、由于 Generator函數(shù)是 “惰性求值”,執(zhí)行到第一個(gè) yield 時(shí)才會(huì)計(jì)算求和思杯,并加計(jì)算結(jié)果返回給遍歷器對(duì)象 {value: 14, done: false}胜蛉,函數(shù)暫停運(yùn)行

(3)、理論上應(yīng)該要把等號(hào)右邊的 [yield 3 + 5 + 6] 賦值給變量result色乾,但是誊册,由于函數(shù)執(zhí)行到 yield 時(shí)暫定了,這一步就被掛起了

第二次調(diào)用next方法暖璧,函數(shù)從上一次 yield 停下的地方開始執(zhí)行解虱,也就是給result賦值的地方開始,由于next()并沒有傳參漆撞,就相當(dāng)于傳參為undefined

[圖片上傳失敗...(image-73e766-1615534021545)]

基于以上分析,就不難理解為什么說 yield表達(dá)式本身的返回值(特指 [rv])總是undefined了∮谥妫現(xiàn)在把上面的代碼稍作修改浮驳,第二次調(diào)用 next() 方法傳一個(gè)參數(shù)3,按照上圖分析可以很快得出輸出結(jié)果

{
  function* gen() {
    let result = yield 3 + 5 + 6
    console.log(result)
    yield result
  }

  let it = gen()
  console.log(it.next())      // {value: 14, done: false}
  console.log(it.next(3))      // 3    {value: 3, done: false}
}

如果第一次調(diào)用next()的時(shí)候也傳了一個(gè)參數(shù)呢捞魁?這個(gè)當(dāng)然是無效的至会,next方法的參數(shù)表示上一個(gè)yield表達(dá)式的返回值,所以在第一次使用next方法時(shí)谱俭,傳遞參數(shù)是無效的奉件。

從語義上講赘来,第一個(gè)next方法用來啟動(dòng)遍歷器對(duì)象耀找,所以不用帶有參數(shù)。

{
  function* gen() {
    let result = yield 3 + 5 + 6
    console.log(result)
    yield result
  }

  let it = gen()
  console.log(it.next(10))      // {value: 14, done: false}
  console.log(it.next(3))      // 3    {value: 3, done: false}
}

Generator 函數(shù)從暫停狀態(tài)到恢復(fù)運(yùn)行,它的上下文狀態(tài)(context)是不變的浴栽。通過next方法的參數(shù),就有辦法在 Generator 函數(shù)開始運(yùn)行之后阿宅,繼續(xù)向函數(shù)體內(nèi)部注入值橡类。也就是說,可以在 Generator 函數(shù)運(yùn)行的不同階段摆碉,從外部向內(nèi)部注入不同的值塘匣,從而調(diào)整函數(shù)行為。

{
  function* gen(x) {
    let y = 2 * (yield (x + 1))   // 注意:yield 表達(dá)式如果用在另一個(gè)表達(dá)式中巷帝,必須放在圓括號(hào)里面
    let z = yield (y / 3)
    return x + y + z
  }

  let it = gen(5)
  /* 通過前面的介紹就知道這部分輸出結(jié)果是錯(cuò)誤的啦
    
    console.log(it.next())  // {value: 6, done: false}
    console.log(it.next())  // {value: 2, done: false}
    console.log(it.next())  // {value: 13, done: false}
  */
  
  /*** 正確的結(jié)果在這里 ***/
  console.log(it.next())  // 首次調(diào)用next忌卤,函數(shù)只會(huì)執(zhí)行到 “yield(5+1)” 暫停,并返回 {value: 6, done: false}
  console.log(it.next())  // 第二次調(diào)用next楞泼,沒有傳遞參數(shù)驰徊,所以 y的值是undefined,那么 y/3 當(dāng)然是一個(gè)NaN现拒,所以應(yīng)該返回 {value: NaN, done: false}
  console.log(it.next())  // 同樣的道理辣垒,z也是undefined,6 + undefined + undefined = NaN印蔬,返回 {value: NaN, done: true}
}

如果向next方法提供參數(shù)勋桶,返回結(jié)果就完全不一樣了

{
  function* gen(x) {
    let y = 2 * (yield (x + 1))   // 注意:yield 表達(dá)式如果用在另一個(gè)表達(dá)式中,必須放在圓括號(hào)里面
    let z = yield (y / 3)
    return x + y + z
  }

  let it = gen(5)

  console.log(it.next())  // 正常的運(yùn)算應(yīng)該是先執(zhí)行圓括號(hào)內(nèi)的計(jì)算侥猬,再去乘以2例驹,由于圓括號(hào)內(nèi)被 yield 返回 5 + 1 的結(jié)果并暫停,所以返回{value: 6, done: false}
  console.log(it.next(9))  // 上次是在圓括號(hào)內(nèi)部暫停的退唠,所以第二次調(diào)用 next方法應(yīng)該從圓括號(hào)里面開始鹃锈,就變成了 let y = 2 * (9),y被賦值為18瞧预,所以第二次返回的應(yīng)該是 18/3的結(jié)果 {value: 6, done: false}
  console.log(it.next(2))  // 參數(shù)2被賦值給了 z屎债,最終 x + y + z = 5 + 18 + 2 = 25,返回 {value: 25, done: true}
}
{
  function* gen(x) {
    let y = 2 * (yield (x + 1))   
    let z = yield (y / 3)
    z = 88    // 注意看這里
    return x + y + z
  }

  let it = gen(5)

  console.log(it.next())   // {value: 6, done: false}
  console.log(it.next(9))  // {value: 6, done: false}
  console.log(it.next(2))  // 這里其實(shí)也很容易理解垢油,參數(shù)2被賦值給了 z盆驹,但是函數(shù)體內(nèi)又給 z 重新賦值為88, 最終 x + y + z = 5 + 18 + 88 = 111滩愁,返回 {value: 111, done: true}
}

五躯喇、與 Iterator 接口的關(guān)系

ES6 規(guī)定,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性硝枉,或者說廉丽,一個(gè)數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性倦微,就可以認(rèn)為是“可遍歷的”(iterable)。

Symbol.iterator屬性本身是一個(gè)函數(shù)正压,就是當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認(rèn)的遍歷器生成函數(shù)欣福。執(zhí)行這個(gè)函數(shù),就會(huì)返回一個(gè)遍歷器蔑匣。

由于執(zhí)行 Generator 函數(shù)實(shí)際返回的是一個(gè)遍歷器劣欢,因此可以把 Generator 賦值給對(duì)象的Symbol.iterator屬性,從而使得該對(duì)象具有 Iterator 接口裁良。

{
  let obj = {}

  function* gen() {
    yield 4
    yield 5
    yield 6
  }

  obj[Symbol.iterator] = gen

  for(let value of obj) {
    console.log(value)
  }
  // 4
  // 5
  // 6

  console.log([...obj])    // [4, 5, 6]
}

傳統(tǒng)對(duì)象沒有原生部署 Iterator接口凿将,不能使用 for...of 和 擴(kuò)展運(yùn)算符,現(xiàn)在通過給對(duì)象添加 Symbol.iterator 屬性和對(duì)應(yīng)的遍歷器生成函數(shù)价脾,就可以使用了

六牧抵、for...of 循環(huán)

由于 Generator 函數(shù)運(yùn)行時(shí)生成的是一個(gè) Iterator 對(duì)象,因此侨把,可以直接使用 for...of 循環(huán)遍歷犀变,且此時(shí)無需再調(diào)用 next() 方法

這里需要注意,一旦 next() 方法的返回對(duì)象的 done 屬性為 true秋柄,for...of 循環(huán)就會(huì)終止获枝,且不包含該返回對(duì)象

{
  function* gen() {
    yield 1
    yield 2
    yield 3
    yield 4
    return 5
  }
  
  for(let item of gen()) {
    console.log(item)
  }
  
  // 1 2 3 4
}

七、Generator.prototype.return()

Generator 函數(shù)返回的遍歷器對(duì)象骇笔,還有一個(gè) return 方法省店,可以返回給定的值(若沒有提供參數(shù),則返回值的value屬性為 undefined)笨触,并且*終結(jié)*遍歷 Generator 函數(shù)

{
  function* gen() {
    yield 1
    yield 2
    yield 3
  }

  let it = gen()

  it.next()             // {value: 1, done: false}
  it.return('ending')   // {value: "ending", done: true}
  it.next()             // {value: undefined, done: true}
}

Generator 函數(shù)應(yīng)用舉例

  • 應(yīng)用一:假定某公司的年會(huì)上有一個(gè)抽獎(jiǎng)活動(dòng)懦傍,總共6個(gè)人可以抽6次,每抽一次芦劣,抽獎(jiǎng)機(jī)會(huì)就會(huì)遞減

    按照常規(guī)做法就需要聲明一個(gè)全局的變量來保存剩余的可抽獎(jiǎng)次數(shù)粗俱,而全局變量會(huì)造成全局污染,指不定什么時(shí)候就被重新賦值了虚吟,所以往往并不被大家推薦

    {
      let count = 6  // 聲明一個(gè)全局變量
    
      // 具體抽獎(jiǎng)邏輯的方法
      function draw() {
        // 執(zhí)行一段抽獎(jiǎng)邏輯
        // ...
        // 執(zhí)行完畢
    
        console.log(`剩余${count}次`)
      }
    
      // 執(zhí)行抽獎(jiǎng)的方法
      function startDrawing(){
        if(count > 0) {
          count--
          draw(count)
        }
      }
    
    
      let btn = document.createElement('button')
      btn.id = 'start'
      btn.textContent = '開始抽獎(jiǎng)'
      document.body.appendChild(btn)
    
      document.getElementById('start').addEventListener('click', function(){
        startDrawing()
      }, false)
    
    }
    
997093-20190426104950172-1768878707.gif

事實(shí)上寸认,抽獎(jiǎng)通常是每個(gè)人自己來抽,每抽一次就調(diào)用一次抽獎(jiǎng)方法串慰,而不是點(diǎn)一次就一次性就全部運(yùn)行完偏塞,是可暫停的,這個(gè)不就是 Generator 函數(shù)的意義所在嗎模庐?

{
  // 具體抽獎(jiǎng)邏輯的方法
  function draw(count) {
    // 執(zhí)行一段抽獎(jiǎng)邏輯
    // ...

    console.log(`剩余${count}次`)
  }

  // 執(zhí)行抽獎(jiǎng)的方法
  function* remain(count) {
    while(count > 0) {
      count--
      yield draw(count)
    }
  }

  let startDrawing = remain(6)

  let btn = document.createElement('button')
  btn.id = 'start'
  btn.textContent = '開始抽獎(jiǎng)'
  document.body.appendChild(btn)

  document.getElementById('start').addEventListener('click', function(){
    startDrawing.next()
  }, false)
}
  • 應(yīng)用二:由于HTTP是一種無狀態(tài)協(xié)議,執(zhí)行一次請(qǐng)求后服務(wù)器無法記住是從哪個(gè)客戶端發(fā)起的請(qǐng)求油宜,因此當(dāng)需要實(shí)時(shí)把服務(wù)器數(shù)據(jù)更新到客戶端時(shí)通常采用的方法是長輪詢和Websocket掂碱。這里也可以用 Generator 函數(shù)來實(shí)現(xiàn)長輪詢

    {
      // 請(qǐng)求的方法
      function* ajax() {
        yield new Promise((resolve, reject) => {
          // 此處用一個(gè)定時(shí)器來模擬請(qǐng)求數(shù)據(jù)的耗時(shí)怜姿,并約定當(dāng)返回的json中code為0表示有新數(shù)據(jù)更新
          setTimeout(() => {
            resolve({code: 0})
          }, 200)
        })
      }
    
      // 長輪詢的方法
      function update() {
        let promise = ajax().next().value    // 返回的對(duì)象的value屬性是一個(gè) Promise 實(shí)例對(duì)象
        promise.then(res => {
          if(res.code != 0) {
            setTimeout(() => {
              console.log('2秒后繼續(xù)查詢.....')
              update()
            }, 2000)
          } else{
            console.log(res)
          }
        })
      }
    
      update()
    }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市疼燥,隨后出現(xiàn)的幾起案子沧卢,更是在濱河造成了極大的恐慌,老刑警劉巖醉者,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件但狭,死亡現(xiàn)場離奇詭異,居然都是意外死亡撬即,警方通過查閱死者的電腦和手機(jī)立磁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剥槐,“玉大人唱歧,你說我怎么就攤上這事×J” “怎么了颅崩?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蕊苗。 經(jīng)常有香客問我沿后,道長,這世上最難降的妖魔是什么朽砰? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任尖滚,我火速辦了婚禮,結(jié)果婚禮上锅移,老公的妹妹穿的比我還像新娘熔掺。我一直安慰自己,他們只是感情好非剃,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布置逻。 她就那樣靜靜地躺著,像睡著了一般备绽。 火紅的嫁衣襯著肌膚如雪券坞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天肺素,我揣著相機(jī)與錄音恨锚,去河邊找鬼。 笑死倍靡,一個(gè)胖子當(dāng)著我的面吹牛猴伶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼他挎,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼筝尾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起办桨,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤筹淫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后呢撞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體损姜,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年殊霞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了摧阅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脓鹃,死狀恐怖逸尖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘸右,我是刑警寧澤娇跟,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站太颤,受9級(jí)特大地震影響苞俘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜龄章,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一吃谣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧做裙,春花似錦岗憋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拧廊,卻和暖如春监徘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吧碾。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工凰盔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倦春。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓户敬,卻偏偏與公主長得像落剪,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尿庐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359