你真的懂Promise嗎

前言

在異步編程中,Promise 扮演了舉足輕重的角色妓忍,比傳統(tǒng)的解決方案(回調函數和事件)更合理和更強大甲喝〕⑽可能有些小伙伴會有這樣的疑問:2020年了,怎么還在談論Promise?事實上糠溜,有些朋友對于這個幾乎每天都在打交道的“老朋友”淳玩,貌似全懂,但稍加深入就可能疑問百出,本文帶大家深入理解這個熟悉的陌生人—— Promise.

基本用法

1.語法

new Promise( function(resolve, reject) {...} /* executor */  )
  • 構建 Promise 對象時非竿,需要傳入一個 executor 函數凯肋,主要業(yè)務流程都在 executor 函數中執(zhí)行。
  • Promise構造函數執(zhí)行時立即調用executor 函數汽馋, resolve 和 reject 兩個函數作為參數傳遞給executor侮东,resolve 和 reject 函數被調用時,分別將promise的狀態(tài)改為fulfilled(完成)或rejected(失敱尽)悄雅。一旦狀態(tài)改變,就不會再變铁蹈,任何時候都可以得到這個結果宽闲。
  • 在 executor 函數中調用 resolve 函數后,會觸發(fā) promise.then 設置的回調函數握牧;而調用 reject 函數后容诬,會觸發(fā) promise.catch 設置的回調函數。
image

值得注意的是沿腰,Promise 是用來管理異步編程的览徒,它本身不是異步的,new Promise的時候會立即把executor函數執(zhí)行颂龙,只不過我們一般會在executor函數中處理一個異步操作习蓬。比如下面代碼中,一開始是會先打印出2措嵌。

let p1 = new Promise(()=>{
    setTimeout(()=>{
      console.log(1)
    },1000)
    console.log(2)
  })
console.log(3) // 2 3 1

Promise 采用了回調函數延遲綁定技術躲叼,在執(zhí)行 resolve 函數的時候,回調函數還沒有綁定企巢,那么只能推遲回調函數的執(zhí)行枫慷。這具體是啥意思呢?我們先來看下面的例子:

let p1 = new Promise((resolve,reject)=>{
  console.log(1);
  resolve('浪里行舟')
  console.log(2)
})
// then:設置成功或者失敗后處理的方法
p1.then(result=>{
 //p1延遲綁定回調函數
  console.log('成功 '+result)
},reason=>{
  console.log('失敗 '+reason)
})
console.log(3)
// 1
// 2
// 3
// 成功 浪里行舟

new Promise的時候先執(zhí)行executor函數浪规,打印出 1或听、2,Promise在執(zhí)行resolve時罗丰,觸發(fā)微任務神帅,還是繼續(xù)往下執(zhí)行同步任務,
執(zhí)行p1.then時萌抵,存儲起來兩個函數(此時這兩個函數還沒有執(zhí)行),然后打印出3找御,此時同步任務執(zhí)行完成元镀,最后執(zhí)行剛剛那個微任務,從而執(zhí)行.then中成功的方法霎桅。

錯誤處理

Promise 對象的錯誤具有“冒泡”性質栖疑,會一直向后傳遞,直到被 onReject 函數處理或 catch 語句捕獲為止滔驶。具備了這樣“冒泡”的特性后遇革,就不需要在每個 Promise 對象中單獨捕獲異常了。

要遇到一個then揭糕,要執(zhí)行成功或者失敗的方法萝快,但如果此方法并沒有在當前then中被定義,則順延到下一個對應的函數

function executor (resolve, reject) {
  let rand = Math.random()
  console.log(1)
  console.log(rand)
  if (rand > 0.5) {
    resolve()
  } else {
    reject()
  }
}
var p0 = new Promise(executor)
var p1 = p0.then((value) => {
  console.log('succeed-1')
  return new Promise(executor)
})
var p2 = p1.then((value) => {
  console.log('succeed-2')
  return new Promise(executor)
})
p2.catch((error) => {
  console.log('error', error)
})
console.log(2)

這段代碼有三個 Promise 對象:p0~p2著角。無論哪個對象里面拋出異常揪漩,都可以通過最后一個對象 p2.catch 來捕獲異常,通過這種方式可以將所有 Promise 對象的錯誤合并到一個函數來處理吏口,這樣就解決了每個任務都需要單獨處理異常的問題奄容。

通過這種方式,我們就消滅了嵌套調用和頻繁的錯誤處理产徊,這樣使得我們寫出來的代碼更加優(yōu)雅昂勒,更加符合人的線性思維。

Promise鏈式調用

我們都知道可以把多個Promise連接到一起來表示一系列異步驟舟铜。這種方式可以實現的關鍵在于以下兩個Promise 固有行為特性:

  • 每次你對Promise調用then戈盈,它都會創(chuàng)建并返回一個新的Promise,我們可以將其鏈接起來深滚;
  • 不管從then調用的完成回調(第一個參數)返回的值是什么奕谭,它都會被自動設置為被鏈接Promise(第一點中的)的完成。

先通過下面的例子痴荐,來解釋一下剛剛這段話是什么意思,然后詳細介紹下鏈式調用的執(zhí)行流程

let p1=new Promise((resolve,reject)=>{
    resolve(100) // 決定了下個then中成功方法會被執(zhí)行
})
// 連接p1
let p2=p1.then(result=>{
    console.log('成功1 '+result)
    return Promise.reject(1) 
// 返回一個新的Promise實例官册,決定了當前實例是失敗的生兆,所以決定下一個then中失敗方法會被執(zhí)行
},reason=>{
    console.log('失敗1 '+reason)
    return 200
})
// 連接p2 
let p3=p2.then(result=>{
    console.log('成功2 '+result)
},reason=>{
    console.log('失敗2 '+reason)
})
// 成功1 100
// 失敗2 1

我們通過返回 Promise.reject(1) ,完成了第一個調用then創(chuàng)建并返回的promise p2膝宁。p2的then調用在運行時會從return Promise.reject(1) 語句接受完成值鸦难。當然,p2.then又創(chuàng)建了另一個新的promise员淫,可以用變量p3存儲合蔽。

new Promise出來的實例,成功或者失敗介返,取決于executor函數執(zhí)行的時候拴事,執(zhí)行的是resolve還是reject決定的沃斤,或executor函數執(zhí)行發(fā)生異常錯誤,這兩種情況都會把實例狀態(tài)改為失敗的刃宵。

p2執(zhí)行then返回的新實例的狀態(tài)衡瓶,決定下一個then中哪一個方法會被執(zhí)行,有以下幾種情況:

  • 不論是成功的方法執(zhí)行牲证,還是失敗的方法執(zhí)行(then中的兩個方法)哮针,凡是執(zhí)行拋出了異常,則都會把實例的狀態(tài)改為失敗坦袍。
  • 方法中如果返回一個新的Promise實例(比如上例中的Promise.reject(1))十厢,返回這個實例的結果是成功還是失敗,也決定了當前實例是成功還是失敗捂齐。
  • 剩下的情況基本上都是讓實例變?yōu)槌晒Φ臓顟B(tài)蛮放,上一個then中方法返回的結果會傳遞到下一個then的方法中。

我們再來看個例子

new Promise(resolve=>{
    resolve(a) // 報錯 
// 這個executor函數執(zhí)行發(fā)生異常錯誤辛燥,決定下個then失敗方法會被執(zhí)行
}).then(result=>{
    console.log(`成功:${result}`)
    return result*10
},reason=>{
    console.log(`失斏肝洹:${reason}`)
// 執(zhí)行這句時候,沒有發(fā)生異晨嫠或者返回一個失敗的Promise實例徘六,所以下個then成功方法會被執(zhí)行
// 這里沒有return,最后會返回 undefined
}).then(result=>{
    console.log(`成功:${result}`)
},reason=>{
    console.log(`失斄穸肌:${reason}`)
})
// 失敶狻:ReferenceError: a is not defined
// 成功:undefined

async & await

從上面一些例子,我們可以看出嘴高,雖然使用 Promise 能很好地解決回調地獄的問題竿音,但是這種方式充滿了 Promise 的 then() 方法,如果處理流程比較復雜的話拴驮,那么整段代碼將充斥著 then春瞬,語義化不明顯,代碼不能很好地表示執(zhí)行流程套啤。

ES7中新增的異步編程方法宽气,async/await的實現是基于 Promise的,簡單而言就是async 函數就是返回Promise對象潜沦,是generator的語法糖萄涯。很多人認為async/await是異步操作的終極解決方案:

  • 語法簡潔,更像是同步代碼唆鸡,也更符合普通的閱讀習慣涝影;
  • 改進JS中異步操作串行執(zhí)行的代碼組織方式,減少callback的嵌套争占;
  • Promise中不能自定義使用try/catch進行錯誤捕獲燃逻,但是在Async/await中可以像處理同步代碼處理錯誤序目。

不過也存在一些缺點,因為 await 將異步代碼改造成了同步代碼唆樊,如果多個異步代碼沒有依賴性卻使用了 await 會導致性能上的降低宛琅。

async function test() {
  // 以下代碼沒有依賴性的話,完全可以使用 Promise.all 的方式
  // 如果有依賴性的話逗旁,其實就是解決回調地獄的例子了
  await fetch(url1)
  await fetch(url2)
  await fetch(url3)
}

觀察下面這段代碼嘿辟,你能判斷出打印出來的內容是什么嗎?

let p1 = Promise.resolve(1)
let p2 = new Promise(resolve => {
  setTimeout(() => {
    resolve(2)
  }, 1000)
})
async function fn() {
  console.log(1)
// 當代碼執(zhí)行到此行(先把此行)片效,構建一個異步的微任務
// 等待promise返回結果红伦,并且await下面的代碼也都被列到任務隊列中
  let result1 = await p2
  console.log(3)
  let result2 = await p1
  console.log(4)
}
fn()
console.log(2)
// 1 2 3 4

如果 await 右側表達邏輯是個 promise,await會等待這個promise的返回結果淀衣,只有返回的狀態(tài)是resolved情況昙读,才會把結果返回,如果promise是失敗狀態(tài),則await不會接收其返回結果膨桥,await下面的代碼也不會在繼續(xù)執(zhí)行蛮浑。

let p1 = Promise.reject(100)
async function fn1() {
  let result = await p1
  console.log(1) //這行代碼不會執(zhí)行
}

我們再來看道比較復雜的題目:

console.log(1)
setTimeout(()=>{console.log(2)},1000)
async function fn(){
    console.log(3)
    setTimeout(()=>{console.log(4)},20)
    return Promise.reject()
}
async function run(){
    console.log(5)
    await fn()
    console.log(6)
}
run()
//需要執(zhí)行150ms左右
for(let i=0;i<90000000;i++){}
setTimeout(()=>{
    console.log(7)
    new Promise(resolve=>{
        console.log(8)
        resolve()
    }).then(()=>{console.log(9)})
},0)
console.log(10)
// 1 5 3 10 4 7 8 9 2

做這道題之前,讀者需明白:

  • 基于微任務的技術有 MutationObserver只嚣、Promise 以及以 Promise 為基礎開發(fā)出來的很多其他的技術沮稚,本題中resolve()、await fn()都是微任務册舞。
  • 不管宏任務是否到達時間蕴掏,以及放置的先后順序,每次主線程執(zhí)行棧為空的時候调鲸,引擎會優(yōu)先處理微任務隊列盛杰,處理完微任務隊列里的所有任務,再去處理宏任務藐石。

接下來即供,我們一步一步分析:

  • 首先執(zhí)行同步代碼,輸出 1于微,遇見第一個setTimeout募狂,將其回調放入任務隊列(宏任務)當中,繼續(xù)往下執(zhí)行
  • 運行run(),打印出 5角雷,并往下執(zhí)行,遇見 await fn()性穿,將其放入任務隊列(微任務)
  • await fn() 當前這一行代碼執(zhí)行時勺三,fn函數會立即執(zhí)行的,打印出3,遇見第二個setTimeout需曾,將其回調放入任務隊列(宏任務)吗坚,await fn() 下面的代碼需要等待返回Promise成功狀態(tài)才會執(zhí)行祈远,所以6是不會被打印的。
  • 繼續(xù)往下執(zhí)行艾船,遇到for循環(huán)同步代碼逊笆,需要等150ms,雖然第二個setTimeout已經到達時間进肯,但不會執(zhí)行,遇見第三個setTimeout扫沼,將其回調放入任務隊列(宏任務),然后打印出10庄吼。值得注意的是缎除,這個定時器 推遲時間0毫秒實際上達不到的。根據HTML5標準总寻,setTimeOut推遲執(zhí)行的時間器罐,最少是4毫秒。
  • 同步代碼執(zhí)行完畢渐行,此時沒有微任務轰坊,就去執(zhí)行宏任務,上面提到已經到點的setTimeout先執(zhí)行祟印,打印出4
  • 然后執(zhí)行下一個setTimeout的宏任務肴沫,所以先打印出7,new Promise的時候會立即把executor函數執(zhí)行旁理,打印出8樊零,然后在執(zhí)行resolve時,觸發(fā)微任務孽文,于是打印出9
  • 最后執(zhí)行第一個setTimeout的宏任務驻襟,打印出2

常用的方法

1、Promise.resolve()

Promise.resolve(value)方法返回一個以給定值解析后的Promise 對象芋哭。
Promise.resolve()等價于下面的寫法:

Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))

Promise.resolve方法的參數分成四種情況沉衣。

(1)參數是一個 Promise 實例

如果參數是 Promise 實例,那么Promise.resolve將不做任何修改减牺、原封不動地返回這個實例豌习。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})
p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

上面代碼中,p1是一個 Promise拔疚,3 秒之后變?yōu)閞ejected肥隆。p2的狀態(tài)在 1 秒之后改變,resolve方法返回的是p1稚失。由于p2返回的是另一個 Promise栋艳,導致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)句各。所以吸占,后面的then語句都變成針對后者(p1)晴叨。又過了 2 秒,p1變?yōu)閞ejected矾屯,導致觸發(fā)catch方法指定的回調函數兼蕊。

(2)參數不是具有then方法的對象,或根本就不是對象

Promise.resolve("Success").then(function(value) {
 // Promise.resolve方法的參數件蚕,會同時傳給回調函數孙技。
  console.log(value); // "Success"
}, function(value) {
  // 不會被調用
});

(3)不帶有任何參數

Promise.resolve()方法允許調用時不帶參數,直接返回一個resolved狀態(tài)的 Promise 對象骤坐。如果希望得到一個 Promise 對象绪杏,比較方便的方法就是直接調用Promise.resolve()方法。

Promise.resolve().then(function () {
  console.log('two');
});
console.log('one');
// one two

(4)參數是一個thenable對象

thenable對象指的是具有then方法的對象,Promise.resolve方法會將這個對象轉為 Promise 對象纽绍,然后就立即執(zhí)行thenable對象的then方法蕾久。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

2、Promise.reject()

Promise.reject()方法返回一個帶有拒絕原因的Promise對象拌夏。

new Promise((resolve,reject) => {
    reject(new Error("出錯了"));
});
// 等價于
 Promise.reject(new Error("出錯了"));  

// 使用方法
Promise.reject(new Error("BOOM!")).catch(error => {
    console.error(error);
});

值得注意的是僧著,調用resolve或reject以后,Promise 的使命就完成了障簿,后繼操作應該放到then方法里面盹愚,而不應該直接寫在resolve或reject的后面。所以站故,最好在它們前面加上return語句皆怕,這樣就不會有意外。

new Promise((resolve, reject) => {
  return reject(1);
  // 后面的語句不會執(zhí)行
  console.log(2);
})

3西篓、Promise.all()

let p1 = Promise.resolve(1)
let p2 = new Promise(resolve => {
  setTimeout(() => {
    resolve(2)
  }, 1000)
})
let p3 = Promise.resolve(3)
Promise.all([p3, p2, p1])
  .then(result => {
 // 返回的結果是按照Array中編寫實例的順序來
    console.log(result) // [ 3, 2, 1 ]
  })
  .catch(reason => {
    console.log("失敗:reason")
  })

Promise.all 生成并返回一個新的 Promise 對象愈腾,所以它可以使用 Promise 實例的所有方法。參數傳遞promise數組中所有的 Promise 對象都變?yōu)閞esolve的時候岂津,該方法才會返回虱黄, 新創(chuàng)建的 Promise 則會使用這些 promise 的值。

如果參數中的任何一個promise為reject的話吮成,則整個Promise.all調用會立即終止橱乱,并返回一個reject的新的 Promise 對象。

4粱甫、Promise.allSettled()

有時候泳叠,我們不關心異步操作的結果,只關心這些操作有沒有結束茶宵。這時析二,ES2020 引入Promise.allSettled()方法就很有用。如果沒有這個方法,想要確保所有操作都結束叶摄,就很麻煩。Promise.all()方法無法做到這一點安拟。

假如有這樣的場景:一個頁面有三個區(qū)域蛤吓,分別對應三個獨立的接口數據,使用 Promise.all 來并發(fā)請求三個接口糠赦,如果其中任意一個接口出現異常会傲,狀態(tài)是reject,這會導致頁面中該三個區(qū)域數據全都無法出來,顯然這種狀況我們是無法接受拙泽,Promise.allSettled的出現就可以解決這個痛點:

Promise.allSettled([
  Promise.reject({ code: 500, msg: '服務異常' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
  /*
    0: {status: "rejected", reason: {…}}
    1: {status: "fulfilled", value: {…}}
    2: {status: "fulfilled", value: {…}}
  */
  // 過濾掉 rejected 狀態(tài)淌山,盡可能多的保證頁面區(qū)域數據渲染
  RenderContent(
    res.filter(el => {
      return el.status !== 'rejected'
    })
  )
})

Promise.allSettled跟Promise.all類似, 其參數接受一個Promise的數組, 返回一個新的Promise, 唯一的不同在于, 它不會進行短路, 也就是說當Promise全部處理完成后,我們可以拿到每個Promise的狀態(tài), 而不管是否處理成功。

5顾瞻、Promise.race()

Promise.all()方法的效果是"誰跑的慢泼疑,以誰為準執(zhí)行回調",那么相對的就有另一個方法"誰跑的快荷荤,以誰為準執(zhí)行回調"退渗,這就是Promise.race()方法,這個詞本來就是賽跑的意思蕴纳。race的用法與all一樣会油,接收一個promise對象數組為參數。

Promise.all在接收到的所有的對象promise都變?yōu)镕ulFilled或者Rejected狀態(tài)之后才會繼續(xù)進行后面的處理古毛,與之相對的是Promise.race只要有一個promise對象進入FulFilled或者Rejected狀態(tài)的話翻翩,就會繼續(xù)進行后面的處理。

// `delay`毫秒后執(zhí)行resolve
function timerPromisefy(delay) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(delay);
        }, delay);
    });
}
// 任何一個promise變?yōu)閞esolve或reject的話程序就停止運行
Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64)
]).then(function (value) {
    console.log(value);    // => 1
});

上面的代碼創(chuàng)建了3個promise對象稻薇,這些promise對象會分別在1ms嫂冻、32ms 和 64ms后變?yōu)榇_定狀態(tài),即FulFilled颖低,并且在第一個變?yōu)榇_定狀態(tài)的1ms后絮吵,.then注冊的回調函數就會被調用。

6忱屑、Promise.prototype.finally()

ES9 新增 finally() 方法返回一個Promise蹬敲。在promise結束時,無論結果是fulfilled或者是rejected莺戒,都會執(zhí)行指定的回調函數伴嗡。這為在Promise是否成功完成后都需要執(zhí)行的代碼提供了一種方式。這避免了同樣的語句需要在then()和catch()中各寫一次的情況从铲。

比如我們發(fā)送請求之前會出現一個loading瘪校,當我們請求發(fā)送完成之后,不管請求有沒有出錯,我們都希望關掉這個loading阱扬。

this.loading = true
request()
  .then((res) => {
    // do something
  })
  .catch(() => {
    // log err
  })
  .finally(() => {
    this.loading = false
  })

finally方法的回調函數不接受任何參數泣懊,這表明,finally方法里面的操作麻惶,應該是與狀態(tài)無關的馍刮,不依賴于 Promise 的執(zhí)行結果。

實際應用

假設有這樣一個需求:紅燈 3s 亮一次窃蹋,綠燈 1s 亮一次卡啰,黃燈 2s 亮一次;如何讓三個燈不斷交替重復亮燈警没?
三個亮燈函數已經存在:

function red() {
    console.log('red');
}
function green() {
    console.log('green');
}
function yellow() {
    console.log('yellow');
}

這道題復雜的地方在于需要“交替重復”亮燈匈辱,而不是亮完一遍就結束的一錘子買賣,我們可以通過遞歸來實現:

// 用 promise 實現
let task = (timer, light) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (light === 'red') {
        red()
      }
      if (light === 'green') {
        green()
      }
      if (light === 'yellow') {
        yellow()
      }
      resolve()
    }, timer);
  })
}
let step = () => {
  task(3000, 'red')
    .then(() => task(1000, 'green'))
    .then(() => task(2000, 'yellow'))
    .then(step)
}
step()

同樣也可以通過async/await 的實現:

//  async/await 實現
let step = async () => {
  await task(3000, 'red')
  await task(1000, 'green')
  await task(2000, 'yellow')
  step()
}
step()

使用 async/await 可以實現用同步代碼的風格來編寫異步代碼,毫無疑問杀迹,還是 async/await 的方案更加直觀亡脸,不過深入理解Promise 是掌握async/await的基礎。

歡迎關注公眾號:前端工匠佛南,你的成長我們一起見證梗掰!

在這里插入圖片描述

參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末嗅回,一起剝皮案震驚了整個濱河市及穗,隨后出現的幾起案子,更是在濱河造成了極大的恐慌绵载,老刑警劉巖埂陆,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異娃豹,居然都是意外死亡焚虱,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門懂版,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹃栽,“玉大人,你說我怎么就攤上這事躯畴∶窆模” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵蓬抄,是天一觀的道長丰嘉。 經常有香客問我,道長嚷缭,這世上最難降的妖魔是什么饮亏? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任耍贾,我火速辦了婚禮,結果婚禮上路幸,老公的妹妹穿的比我還像新娘荐开。我一直安慰自己,他們只是感情好劝赔,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布誓焦。 她就那樣靜靜地躺著,像睡著了一般着帽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上移层,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天仍翰,我揣著相機與錄音,去河邊找鬼观话。 笑死予借,一個胖子當著我的面吹牛,可吹牛的內容都是我干的频蛔。 我是一名探鬼主播灵迫,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晦溪!你這毒婦竟也來了瀑粥?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤三圆,失蹤者是張志新(化名)和其女友劉穎狞换,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體舟肉,經...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡修噪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了路媚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黄琼。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖整慎,靈堂內的尸體忽然破棺而出脏款,到底是詐尸還是另有隱情,我是刑警寧澤院领,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布弛矛,位于F島的核電站,受9級特大地震影響比然,放射性物質發(fā)生泄漏丈氓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望万俗。 院中可真熱鬧湾笛,春花似錦、人聲如沸闰歪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽库倘。三九已至临扮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間教翩,已是汗流浹背杆勇。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饱亿,地道東北人蚜退。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像彪笼,于是被迫代替她去往敵國和親钻注。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353