啥篮昧?喝著闊落吃著西瓜就把Promise手寫出來了赋荆??懊昨?

前言

雖然今年已經(jīng)18年窄潭,但是今天還是要繼續(xù)聊聊ES6的東西,ES6已經(jīng)過去幾年酵颁,可是我們對于ES6的語法究竟是掌握了什么程度嫉你,是了解?會用躏惋?還是精通幽污?相信大家和我一樣都對自己有著一個提升的心,對于新玩具可不能僅僅了解簿姨,對于其中的思想才是最吸引人的距误,所以接下來會通過一篇文章,來讓大家對于Promise這個玩具做到精通的程度1馕弧W继丁!


此處打開一瓶冰闊落~~~

Promise

Promise 是異步編程的一種解決方案域仇,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大刑然。它由社區(qū)最早提出和實現(xiàn),ES6將其寫進(jìn)了語言標(biāo)準(zhǔn)暇务,統(tǒng)一了用法泼掠,原生提供了Promise對象。

嗝~~~~~

首先垦细,我們通過字面可以看出來Pormise是一種解決方案择镇,而且還有兩種傳統(tǒng)的解決方案·回調(diào)函數(shù)事件,ok蝠检,那么我們就來先聊聊這兩種方案沐鼠。

回調(diào)函數(shù) Callback

回調(diào)函數(shù)想必大家都不陌生,就是我們常見的把一個函數(shù)當(dāng)做參數(shù)傳遞給另外一個函數(shù)叹谁,在滿足了一定的條件之后再去執(zhí)行回調(diào),比如我們想要實現(xiàn)一個在三秒后去計算1到5的和乘盖,那么:

    // 求和函數(shù)
    function sum () {
        return eval([...arguments].join('+'))
    }
    // 三秒后執(zhí)行函數(shù)
    function asycnGetSum (callback) {
        setTimeout(function(){
            var result = callback(1,2,3,4,5);
            console.log(result)
        },3000)
    }
    asyncGetSum(sum);

這樣的實現(xiàn)就是回調(diào)函數(shù)焰檩,但是如果我要實現(xiàn)在一段動畫,動畫的執(zhí)行過程是小球先向右移動100px订框,然后再向下移動100px析苫,在向左移動100px,每段動畫持續(xù)時間都是3s.

    dom.animate({left:'100px'},3000,'linear',function(){
        dom.animate({top:'100px'},3000,'linear',function(){
            dom.animate({left:'0px'},3000,'linear',function(){
                console.log('動畫 done')
            })
        })
    })

這樣就會看到形成了一個回調(diào)嵌套,也就是我們常說的回調(diào)地獄衩侥,導(dǎo)致代碼可讀性十分差国旷。

事件

事件處理就是jQuery中的on綁定事件和trigger觸發(fā)事件,其實就是我們常見的發(fā)布訂閱模式茫死,當(dāng)我訂閱了一個事件跪但,那么我就是訂閱者,如果發(fā)布者發(fā)布了數(shù)據(jù)之后峦萎,那么我就要收到相應(yīng)的通知屡久。

    // 定義一個發(fā)布中心
    let publishCenter = {
        subscribeArrays:{}, // 定義一個訂閱者回調(diào)函數(shù)callback
        subscribe:function(key,callback){
            // 增加訂閱者
            if(!this.subscribeArrays[key]){
                this.subscribeArrays[key] = [];
            }
            this.subscribeArrays[key].push(callback)
        },
        publish:function(){
            //發(fā)布 第一個參數(shù)是key
            let params = [...arguments];
            let key = params.shift();
            let callbacks = this.subscribeArrays[key];
            if(!callbacks || callbacks.length === 0){
                // 如果沒人訂閱 那么就返回
                return false
            }
            for( let i = 0 ; i < callbacks.length; i++ ){
                callbacks[i].apply( this, params );
            }
        }
    };
    
    // 訂閱 一個wantWatermelon事件
    publishCenter.subscribe('wantWatermelon',function(){console.log('恰西瓜咯~~')})
    
    //觸發(fā)wantWatermelon事件 好咯 可以看到 恰西瓜咯
    publishCenter.publish('wantWatermelon')



恰西瓜中~~~

Promise A+

嗝~ok,吃完我們進(jìn)入正題爱榔,看到上面異步編程如此如此如此麻煩被环,對于我這種頭大用戶,當(dāng)然是拒絕的啊详幽,還好我們有PormisePormise大法好),下面我們就來通過實現(xiàn)一個Promise去更深的了解Promise的原理筛欢,首先我們了解一下PromiseA+,它是一種規(guī)范唇聘,用來約束大家寫的Promise方法的版姑,為了讓大家寫的Promise杜絕一些錯誤,按照我們所期望的流程來走雳灾,因此就出現(xiàn)了PromiseA+規(guī)范漠酿。

Promise特點

我們根據(jù)PromiseA+文檔來一步一步的看Promise有什么特點。

首先我們看文檔的2.1節(jié)谎亩,題目是Promise states炒嘲,也就是說講的是Promise的狀態(tài),那么都說了些什么呢匈庭,我們來看一哈:

  • 一個promise只有三種狀態(tài)夫凸,pending態(tài),fulfilled態(tài)(完成態(tài)),rejected(拒絕態(tài))
  • 當(dāng)promise處于pending態(tài)時阱持,可能轉(zhuǎn)化成fulfilled或者rejected
  • 一旦promise的狀態(tài)改成了fulfilled后夭拌,狀態(tài)就不能再改變了,并且需要提供一個不可變的value
  • 一旦promise的狀態(tài)改成了rejected后衷咽,狀態(tài)就不能再改變了鸽扁,并且需要提供一個不可變的reason

ok,那么我們就開始寫我們自己的Promise,我們先看看一段正常Promise的寫法

    // 成功或者失敗是需要提供一個value或者reason
    let promise1 = new Promise((resolve,rejected)=>{
        // 可以發(fā)現(xiàn) 當(dāng)我們new Promise的時候這句話是同步執(zhí)行的 也就是說當(dāng)我們初始化一個promise的時候 內(nèi)部的回調(diào)函數(shù)(通常我們叫做執(zhí)行器executor)會立即執(zhí)行
        console.log('hahahha');
        // promise內(nèi)部支持異步
        setTimeout(function(){
            resolve(123);
        },100)
        // throw new Error('error') 我們也可以在執(zhí)行器內(nèi)部直接拋出一個錯誤 這時promise會直接變成rejected態(tài)
    })
    

根據(jù)我們上面的代碼還有PromiseA+規(guī)范中的狀態(tài)說明镶骗,我們可以知道Promise已經(jīng)有了下面幾個特點

  1. promise有三種狀態(tài) 默認(rèn)pending態(tài) pending可以變成fulfilled(成功態(tài))或者rejected(失敗態(tài))桶现,而一旦轉(zhuǎn)變之后就不能在變成其他值了
  2. promise內(nèi)部有一個value 用來存儲成功態(tài)的結(jié)果
  3. promise內(nèi)部有一個reason 用來存儲失敗態(tài)的原因
  4. promise接受一個executor函數(shù),這個函數(shù)有兩個參數(shù)鼎姊,一個是resolve方法骡和,一個是reject方法相赁,當(dāng)執(zhí)行resolve時,promise狀態(tài)改變?yōu)?code>fulfilled慰于,執(zhí)行reject時钮科,promise狀態(tài)改變?yōu)?code>rejected
  5. 默認(rèn) new Promise 執(zhí)行的時候內(nèi)部的executor函數(shù)執(zhí)行
  6. promise內(nèi)部支持異步改變狀態(tài)
  7. promise內(nèi)部支持拋出異常,那么該promise的狀態(tài)直接改成rejected

我們接下來繼續(xù)看PromiseA+文檔:

  • promise必須要有一個then方法婆赠,用來訪問它當(dāng)前的value或者是reason
  • 該方法接受兩個參數(shù)onFulfilled(成功回掉函數(shù))绵脯,onRejected(失敗回調(diào)函數(shù)) promise.then(onFulfilled, onRejected)
  • 這兩個參數(shù)都是可選參數(shù),如果發(fā)現(xiàn)這兩個參數(shù)不是函數(shù)類型的話页藻,那么就忽略 比如 promise.then().then(data=>console.log(data),err=>console.log(err)) 就可以形成一個值穿透
  • onFulfilled必須在promise狀態(tài)改成fulfilled之后改成調(diào)用桨嫁,并且呢promise內(nèi)部的value值是這個函數(shù)的參數(shù),而且這個函數(shù)不能重復(fù)調(diào)用
  • onRejected必須在promise狀態(tài)改成rejected之后改成調(diào)用份帐,并且呢promise內(nèi)部的reason值是這個函數(shù)的參數(shù)璃吧,而且這個函數(shù)不能重復(fù)調(diào)用
  • onFulfilledonRejected這兩個方法必須要在當(dāng)前執(zhí)行棧的上下文執(zhí)行完畢后再調(diào)用,其實就是事件循環(huán)中的微任務(wù)(setTimeout是宏任務(wù)废境,有一定的差異)
  • onFulfilledonRejected這兩個方法必須通過函數(shù)調(diào)用畜挨,也就是說 他們倆不是通過this.onFulfilled()或者this.onRejected()調(diào)用,直接onFulfilled()或者onRejected()
  • then方法可以在一個promise上多次調(diào)用噩凹,也就是我們常見的鏈?zhǔn)秸{(diào)用
  • 如果當(dāng)前promise的狀態(tài)改成了fulfilled那么就要按照順序依次執(zhí)行then方法中的onFulfilled回調(diào)
  • 如果當(dāng)前promise的狀態(tài)改成了rejected那么就要按照順序依次執(zhí)行then方法中的onRejected回調(diào)
  • then方法必須返回一個promise(接下來我們會把這個promise稱做promise2)巴元,類似于 promise2 = promise1.then(onFulfilled, onRejected);
  • 如果呢onFulfilled()或者onRejected()任一一個返回一個值x,那么就要去執(zhí)行resolvePromise這個函數(shù)中去(這個函數(shù)是用來處理返回值x遇到的各種值驮宴,然后根據(jù)這些值去決定我們剛剛then方法中onFulfilled()或者onRejected()這兩個回調(diào)返回的promise2的狀態(tài))
  • 如果我們在then中執(zhí)行onFulfilled()或者onRejected()方法時產(chǎn)生了異常逮刨,那么就將promise2用異常的原因ereject
  • 如果onFulfilled或者onRejected不是函數(shù),并且promise的狀態(tài)已經(jīng)改成了fulfilled或者rejected堵泽,那么就用同樣的value或者reason去更新promise2的狀態(tài)(其實這一條和第三條一個道理修己,也就是值得穿透問題)

好吧,我們總結(jié)了這么多規(guī)范特點迎罗,那么我們就用這些先來練練手

    /**
     * 實現(xiàn)一個PromiseA+
     * @description 實現(xiàn)一個簡要的promise
     * @param {Function} executor 執(zhí)行器
     * @author Leslie
     */
    function Promise(executor){
        let self = this;
        self.status = 'pending'; // 存儲promise狀態(tài) pending fulfilled rejected.
        self.value = undefined; // 存儲成功后的值
        self.reason = undefined; // 記錄失敗的原因
        self.onfulfilledCallbacks = []; //  異步時候收集成功回調(diào)
        self.onrejectedCallbacks = []; //  異步時候收集失敗回調(diào)
        function resolve(value){
            if(self.status === 'pending'){
                self.status = 'fulfilled';// resolve的時候改變promise的狀態(tài)
                self.value = value;//修改成功的值
                // 異步執(zhí)行后 調(diào)用resolve 再把存儲的then中的成功回調(diào)函數(shù)執(zhí)行一遍
                self.onfulfilledCallbacks.forEach(element => {
                    element()
                });
            }
        }
        function reject(reason){
            if(self.status === 'pending'){
                self.status = 'rejected';// reject的時候改變promise的狀態(tài)
                self.reason = reason; // 修改失敗的原因
                // 異步執(zhí)行后 調(diào)用reject 再把存儲的then中的失敗回調(diào)函數(shù)執(zhí)行一遍
                self.onrejectedCallbacks.forEach(element => {
                    element()
                });
            }
        }
        // 如果執(zhí)行器中拋出異常 那么就把promise的狀態(tài)用這個異常reject掉
        try {
            //執(zhí)行 執(zhí)行器
            executor(resolve,reject);
        } catch (error) {
            reject(error)
        }
    }

    Promise.prototype.then = function(onfulfilled,onrejected){
        // onfulfilled then方法中的成功回調(diào)
        // onrejected then方法中的失敗回調(diào)
        let self = this;
        // 如果onfulfilled不是函數(shù) 那么就用默認(rèn)的函數(shù)替代 以便達(dá)到值穿透
        onfulfilled = typeof onfulfilled === 'function'?onfulfilled:val=>val;
        // 如果onrejected不是函數(shù) 那么就用默認(rèn)的函數(shù)替代 以便達(dá)到值穿透
        onrejected = typeof onrejected === 'function'?onrejected: err=>{throw err}
        let promise2 = new Promise((resolve,reject)=>{
            if(self.status === 'fulfilled'){
                // 加入setTimeout 模擬異步
                // 如果調(diào)用then的時候promise 的狀態(tài)已經(jīng)變成了fulfilled 那么就調(diào)用成功回調(diào) 并且傳遞參數(shù)為 成功的value
                setTimeout(function(){
                    // 如果執(zhí)行回調(diào)發(fā)生了異常 那么就用這個異常作為promise2的失敗原因
                    try {
                        // x 是執(zhí)行成功回調(diào)的結(jié)果
                        let x = onfulfilled(self.value);
                        // 調(diào)用resolvePromise函數(shù) 根據(jù)x的值 來決定promise2的狀態(tài)
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (error) {
                        reject(error)
                    }
                },0)
                
            }
        
            if(self.status === 'rejected'){
                // 加入setTimeout 模擬異步
                // 如果調(diào)用then的時候promise 的狀態(tài)已經(jīng)變成了rejected 那么就調(diào)用失敗回調(diào) 并且傳遞參數(shù)為 失敗的reason
                setTimeout(function(){
                    // 如果執(zhí)行回調(diào)發(fā)生了異常 那么就用這個異常作為promise2的失敗原因
                    try {
                        // x 是執(zhí)行失敗回調(diào)的結(jié)果
                        let x = onrejected(self.reason);
                         // 調(diào)用resolvePromise函數(shù) 根據(jù)x的值 來決定promise2的狀態(tài)
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
            }
        
            if(self.status === 'pending'){
                //如果調(diào)用then的時候promise的狀態(tài)還是pending睬愤,說明promsie執(zhí)行器內(nèi)部的resolve或者reject是異步執(zhí)行的,那么就需要先把then方法中的成功回調(diào)和失敗回調(diào)存儲襲來纹安,等待promise的狀態(tài)改成fulfilled或者rejected時候再按順序執(zhí)行相關(guān)回調(diào)
                self.onfulfilledCallbacks.push(()=>{
                    //setTimeout模擬異步
                    setTimeout(function(){
                        // 如果執(zhí)行回調(diào)發(fā)生了異常 那么就用這個異常作為promise2的失敗原因
                        try {
                             // x 是執(zhí)行成功回調(diào)的結(jié)果
                            let x = onfulfilled(self.value)
                            // 調(diào)用resolvePromise函數(shù) 根據(jù)x的值 來決定promise2的狀態(tài)
                            resolvePromise(promise2,x,resolve,reject);
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                })
                self.onrejectedCallbacks.push(()=>{
                    //setTimeout模擬異步
                    setTimeout(function(){
                        // 如果執(zhí)行回調(diào)發(fā)生了異常 那么就用這個異常作為promise2的失敗原因
                        try {
                             // x 是執(zhí)行失敗回調(diào)的結(jié)果
                            let x = onrejected(self.reason)
                             // 調(diào)用resolvePromise函數(shù) 根據(jù)x的值 來決定promise2的狀態(tài)
                            resolvePromise(promise2,x,resolve,reject);
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                })
            }
        })
        return promise2;
    }

一氣呵成尤辱,是不是覺得之前總結(jié)出的特點十分有效,對著特點十分順暢的就擼完了代碼~

那么就讓我們接著來看看promiseA+文檔里還有些什么內(nèi)容吧

  • resolvePromise這個函數(shù)呢會決定promise2用什么樣的狀態(tài)厢岂,如果x是一個普通值光督,那么就直接采用x,如果x是一個promise那么就將這個promise的狀態(tài)當(dāng)成是promise2的狀態(tài)
  • 判斷如果xpromise2是一個對象塔粒,即promise2 === x可帽,那么就陷入了循環(huán)調(diào)用,這時候promise2就會以一個TypeErrorreason轉(zhuǎn)化為rejected
  • 如果x是一個promise窗怒,那么promise2就采用x的狀態(tài)映跟,用和x相同的valueresolve,或者用和x相同的reasonreject
  • 如果x是一個對象或者是函數(shù) 那么就先執(zhí)行let then = x.then
  • 如果x不是一個對象或者函數(shù) 那么就resolve 這個x
  • 如果在執(zhí)行上面的語句中報錯了扬虚,那么就用這個錯誤原因去reject promise2
  • 如果then是一個函數(shù)努隙,那么就執(zhí)行then.call(x,resolveCallback,rejectCallback)
  • 如果then不是一個函數(shù),那么就resolve這個x
  • 如果xfulfilled態(tài) 那么就會走resolveCallback這個函數(shù)辜昵,這時候就默認(rèn)把成功的value作為參數(shù)y傳遞給resolveCallback,即y=>resolvePromise(promise2,y),繼續(xù)調(diào)用resolvePromise這個函數(shù) 確保 返回值是一個普通值而不是promise
  • 如果xrejected態(tài) 那么就把這個失敗的原因reason作為promise2的失敗原因reject出去
  • 如果resolveCallback,rejectCallback這兩個函數(shù)已經(jīng)被調(diào)用了荸镊,或者多次被相同的參數(shù)調(diào)用,那么就確保只調(diào)第一次堪置,剩下的都忽略掉
  • 如果調(diào)用then拋出異常了躬存,并且如果resolveCallback,rejectCallback這兩個函數(shù)已經(jīng)被調(diào)用了,那么就忽略這個異常舀锨,否則就用這個異常作為promise2reject原因

我們又又又又又又總結(jié)了這么多岭洲,好吧不說了總結(jié)多少就開擼吧。

/**
 * 用來處理then方法返回結(jié)果包裝成promise 方便鏈?zhǔn)秸{(diào)用
 * @param {*} promise2 then方法執(zhí)行產(chǎn)生的promise 方便鏈?zhǔn)秸{(diào)用
 * @param {*} x then方法執(zhí)行完成功回調(diào)或者失敗回調(diào)后的result
 * @param {*} resolve 返回的promise的resolve方法 用來更改promise最后的狀態(tài)
 * @param {*} reject 返回的promise的reject方法 用來更改promise最后的狀態(tài)
 */
function resolvePromise(promise2,x,resolve,reject){
    // 首先判斷x和promise2是否是同一引用 如果是 那么就用一個類型錯誤作為Promise2的失敗原因reject
    if( promise2 === x) return reject(new TypeError('typeError:大佬坎匿,你循環(huán)引用了!'));
    // called 用來記錄promise2的狀態(tài)改變盾剩,一旦發(fā)生改變了 就不允許 再改成其他狀態(tài)
    let called;
    if( x !== null && ( typeof x === 'object' || typeof x === 'function')){
        // 如果x是一個對象或者函數(shù) 那么他就有可能是promise 需要注意 null typeof也是 object 所以需要排除掉
        //先獲得x中的then 如果這一步發(fā)生異常了,那么就直接把異常原因reject掉
        try {
            let then = x.then;//防止別人瞎寫報錯
            if(typeof then === 'function'){
                //如果then是個函數(shù) 那么就調(diào)用then 并且把成功回調(diào)和失敗回調(diào)傳進(jìn)去替蔬,如果x是一個promise 并且最終狀態(tài)時成功告私,那么就會執(zhí)行成功的回調(diào),如果失敗就會執(zhí)行失敗的回調(diào)如果失敗了承桥,就把失敗的原因reject出去驻粟,做為promise2的失敗原因,如果成功了那么成功的value時y凶异,這個y有可能仍然是promise蜀撑,所以需要遞歸調(diào)用resolvePromise這個方法 直達(dá)返回值不是一個promise
                then.call(x,y => {
                    if(called) return;
                    called = true;
                    resolvePromise(promise2,y,resolve,reject)
                }, error=>{
                    if(called) return
                    called = true;
                    reject(error)
                })
            }else{
                resolve(x)
            }
        } catch (error) {
            if(called) return
            called = true;
            reject(error)
        }
    }else{
        // 如果是一個普通值 那么就直接把x作為promise2的成功value resolve掉
        resolve(x)
    }

}

finnnnnnnnnally,我們終于通過我們的不懈努力實現(xiàn)了一個基于PromiseA+規(guī)范的Promise

最后呢為了完美唠帝,我們還要在這個promise上實現(xiàn)Promise.resolve,Promise.reject,以及catch屯掖,Promise.allPromise.race這些方法。

Promise的一些方法

Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        resolve(value)
    })
}
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason)
    })
}
Promise.prototype.catch = function(onRejected){
    return this.then(null,onRejected)
}
Promise.all = function(promises){
    return new Promise((resolve,reject)=>{
        let arr = [];
        let i = 0;
        function getResult(index,value){
            arr[index] = value;
            if(++i == promises.length) {
                resolve(arr)
            }
        }
        for(let i = 0;i<promises.length;i++){
            promises[i].then(data=>{
                getResult(i,data)
            },reject)
        }
    })
}
Promise.race = function(promises){
    return new Promise((resolve,reject)=>{
        for(let i = 0 ; i < promises.length ; i++){
            promises[i].then(resolve,reject)
        }
    })
}

Promise 語法糖

恰完西瓜來口糖襟衰,語法糖是為了讓我們書寫promise的時候能夠更加的快速贴铜,所以做了一層改變,我們來看一個例子瀑晒,比如當(dāng)我們封裝一個異步讀取圖片的寬高函數(shù)

    // 原來的方式
    let getImgWidthHeight = function(imgUrl){
        return new Promise((resolve,reject)=>{
            let img = new Image();
            img.onload = function(){
                resolve(img.width+'-'+img.height)
            }
            img.onerror = function(e){
                reject(e)
            }
            img.src = imgUrl;
        })
    }

是不是覺得怎么寫起來有點舒服但又有點不舒服绍坝,好像我每次都要去寫執(zhí)行器啊苔悦!為什么轩褐!好的,沒有為什么玖详,既然不舒服 我們就改!

// 實現(xiàn)一個promise的語法糖
Promise.defer = Promise.deferred = function (){
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd
}

有了上面的語法糖我們再看一下那個圖片的函數(shù)怎么寫

    let newGetImgWidthHeight = function(imgUrl){
        let dfd = Promise.defer();
        let img = new Image();
        img.onload = function(){
            dfd.resolve(img.width+'-'+img.height)
        }
        img.onerror = function(e){
            dfd.reject(e)
        }
        img.url = imgUrl;
        return dfd.promise
    }

是不是發(fā)現(xiàn)我們少了一層函數(shù)嵌套把介,呼~~ 得勁~~

最終檢測

npm install promises-aplus-tests -g

既然我們都說了我們是遵循promiseA+規(guī)范的勤讽,那至少要拿出點證據(jù)來是不是,不然是不是說服不了大家拗踢,那么我們就用promises-aplus-tests這個包來檢測我們寫的promise究竟怎么樣呢脚牍!安裝完成之后來跑一下我們的promise

image

最終跑出來我們?nèi)客ㄟ^測試!酷巢墅!晚餐再加個雞腿~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诸狭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子君纫,更是在濱河造成了極大的恐慌驯遇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓄髓,死亡現(xiàn)場離奇詭異叉庐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)双吆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門眨唬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人好乐,你說我怎么就攤上這事匾竿。” “怎么了蔚万?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵岭妖,是天一觀的道長。 經(jīng)常有香客問我反璃,道長昵慌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任淮蜈,我火速辦了婚禮斋攀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梧田。我一直安慰自己淳蔼,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布裁眯。 她就那樣靜靜地躺著鹉梨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪穿稳。 梳的紋絲不亂的頭發(fā)上存皂,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音逢艘,去河邊找鬼旦袋。 笑死骤菠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的猜憎。 我是一名探鬼主播娩怎,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胰柑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起爬泥,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柬讨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后袍啡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踩官,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年境输,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔗牡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡嗅剖,死狀恐怖辩越,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情信粮,我是刑警寧澤黔攒,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站强缘,受9級特大地震影響督惰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旅掂,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一赏胚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧商虐,春花似錦觉阅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲫尊,卻和暖如春痴柔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疫向。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工咳蔚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留豪嚎,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓谈火,卻偏偏與公主長得像侈询,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子糯耍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354