前端戰(zhàn)五渣學(xué)JavaScript——防抖、節(jié)流和rAF

看了《JavaScript高級程序設(shè)計》和網(wǎng)上的一些博客,感覺對函數(shù)節(jié)流和函數(shù)防抖的概念是反的鼓鲁,以下我寫的關(guān)于防抖和節(jié)流的概念取決于多數(shù)人的概念吧履肃,并且基于倫敦前端工程師David Corbacho的客座文章。文章寫的很好坐桩,并且有對應(yīng)的代碼可以操作尺棋,更容易理解。其實我覺得叫什么不重要绵跷,這個方法叫節(jié)流還是這個方法叫防抖膘螟,只要你能說明白,并且在生產(chǎn)中能用上就可以碾局,一個名字荆残,不用太去糾結(jié)。

《復(fù)仇者聯(lián)盟4:終局之戰(zhàn)》代表著一個時代的結(jié)束净当,從2008年高二看300多MB的《鋼鐵俠》開始内斯,漫威電影宇宙也像哈利波特的魔法世界一樣一路伴我前行。一個時代的落幕像啼,必將開始一個新的時代俘闯。End Game?忽冻?No真朗!

I LOVE YOU THREE THOUSANDS TIMES

I AM IRON MAN

banner獻(xiàn)給復(fù)仇者聯(lián)盟的超級英雄們

banner獻(xiàn)給復(fù)仇者聯(lián)盟的超級英雄們??????

為什么要防抖和節(jié)流?僧诚?

防抖節(jié)流是兩個相似的技術(shù)遮婶,都是為了減少一個函數(shù)無用的觸發(fā)次數(shù),以便提高性能或者說避免資源浪費(fèi)湖笨。我們都知道js在操作DOM的時候旗扑,代價非常昂貴,相對于非DOM操作需要更多的內(nèi)存和和CPU時間慈省,假如我們一個函數(shù)是在滾動滾動條或者更改更改窗口大小的時候頻繁觸發(fā)臀防,還是會出現(xiàn)頁面卡頓,如果是一套復(fù)雜的操作DOM邏輯辫呻,可能還會引起瀏覽器崩潰清钥。所以我們需要控制一下觸發(fā)的次數(shù),來優(yōu)化一下代碼執(zhí)行情況放闺。

口說無憑,大家可能也不了解到底是怎樣操作缕坎,那就來個例子:??


image
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>我要節(jié)流</title>
  <style>
    body{ height: 3000px; }
    #centerNum { width: 100px; height: 100px; line-height: 100px; text-align: center; position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); }
  </style>
</head>
<body>
  <h1 id="centerNum">0</h1>
  <script>
    var num = 0;
    window.onscroll = function () {
      var root = document.getElementsByTagName('body'),
      h = document.getElementById('centerNum');
      h.innerHTML = num;
      num ++;
    }
  </script>
</body>
</html>

我們來一個window.onscroll的函數(shù)怖侦,只要滾動,就改變一次<h1>標(biāo)簽中的數(shù),在上面的圖中匾寝,我們能看到這個觸發(fā)是非常頻繁的搬葬,如果我們不加以干涉的話,讓這個函數(shù)肆意觸發(fā)艳悔,豈不是要上天了??

Debounce 防抖

什么是防抖

啥是防抖呢急凰?我自己的理解就是,當(dāng)連續(xù)觸發(fā)一個方法的時候猜年,方法并不執(zhí)行抡锈,而是在連續(xù)觸發(fā)結(jié)束的時候再執(zhí)行這個方法。

舉個例子:一部直梯乔外,陸續(xù)往上上人(連續(xù)觸發(fā))床三,當(dāng)不再上人的時候(停止連續(xù)觸發(fā)),電梯才會關(guān)門并動起來(執(zhí)行方法)杨幼。

如何實現(xiàn)呢

image

上面是我模擬電梯上人的例子做出來的撇簿,可能這樣看的比較直觀一些,下面有我實現(xiàn)的代碼差购,大概意思就是當(dāng)我上人以后四瘫,電梯啟動,當(dāng)我一直在上人的時候欲逃,電梯不動直到不再上人了离福,才會關(guān)門啟動

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>電梯上人</title>
  <style>

  </style>
</head>
<body>
  <button id="addBtn">電梯上人附鸽,人數(shù)+1</button><button id="resetBtn">重置</button>
  <p id="personNum">電梯人數(shù):0(假設(shè)電梯可以無限裝人)</p>
  <p id="elevatorStatus">電梯停靠</p>
  <script>
    var personNum = 0; // 電梯人數(shù)
    var closeDoor = null; // 電梯啟動延時程序
    var addBtn = document.getElementById('addBtn'); // 獲取添加人數(shù)按鈕
    var personNumP = document.getElementById('personNum'); // 獲取顯示人數(shù)的標(biāo)簽
    var resetBtn = document.getElementById('resetBtn'); // 獲取重置按鈕
    var elevatorStatus = document.getElementById('elevatorStatus'); // 獲取電梯狀態(tài)標(biāo)簽
    /**
     * @method 電梯內(nèi)添加人數(shù)
     * @description 點擊一次電梯內(nèi)增加一人,增加完人數(shù)電梯啟動初始化
     */
    function addPerson() {
      personNum ++;
      personNumP.innerHTML = `電梯人數(shù):${personNum}(假設(shè)電梯可以無限裝人)`
      initElevatorStart();
    }
    /**
     * @method 電梯啟動
     * @description 電梯啟動挖函,置灰添加人數(shù)按鈕,禁止上人
     */
    function elevatorStart() {
      elevatorStatus.innerHTML = '電梯啟動';
      addBtn.disabled = true;
    }
    /**
     * @method 電梯啟動初始化
     * @description 清除之前的關(guān)門延時袍祖,并重新計算關(guān)門延時500ms怖辆,意思是當(dāng)不在觸發(fā)電梯啟動初始化函數(shù)時,500ms后啟動電梯
     */
    function initElevatorStart() {
      clearTimeout(closeDoor);
      closeDoor = setTimeout(function () {
        elevatorStart();
      }, 500);
    }
    /**
     * @method 重置電梯
     */
    function reset() {
      personNum = 0;
      personNumP.innerHTML = `電梯人數(shù):${personNum}(假設(shè)電梯可以無限裝人)`
      elevatorStatus.innerHTML = '電梯驮2ぃ靠';
      addBtn.disabled = false;
    }

    addBtn.addEventListener('click', addPerson);
    resetBtn.addEventListener('click', reset);
  </script>
</body>
</html>

上面的代碼意思就是我電梯上一個人咬清,就需要關(guān)閉電梯門(觸發(fā)initElevatorStart()方法),然后電梯啟動奴潘。但是我一直在點擊上人的按鈕旧烧,電梯是不會觸發(fā)關(guān)門啟動電梯的elevatorStart()方法。

代碼的核心是initElevatorStart()方法画髓,這個方法在實際需要執(zhí)行的關(guān)門啟動電梯方法elevatorStart()外面添加了一層setTimeout方法掘剪,也就是為了在調(diào)用這個方法的時候我們過500毫秒再去執(zhí)行真正需要執(zhí)行的方法。如果這500毫秒之內(nèi)奈虾,又重新觸發(fā)了initElevatorStart()方法夺谁,就需要重新計時廉赔,要不不就夾到人了嘛,要賠錢的匾鸥。蜡塌。。勿负。

這是防抖最粗糙的實現(xiàn)了??????

基本形式

下面是這個防抖實現(xiàn)的最基本的形式馏艾,也是我們在《JavaScript高級程序設(shè)計》中看到的樣子??

var processor = {
  timeoutId: null, // 相當(dāng)于延時setTimeout的一個標(biāo)記,方便清除的時候使用

  // 實際進(jìn)行處理的方法
  // 連續(xù)觸發(fā)停止以后需要觸發(fā)的代碼
  performProcessiong: function () {
    // 實際執(zhí)行的代碼
    // 這里實際就是需要在停止觸發(fā)的時候執(zhí)行的代碼
  },

  // 初始處理調(diào)用的方法
  // 在實際需要觸發(fā)的代碼外面包一層延時clearTimeout方法奴愉,以便控制連續(xù)觸發(fā)帶來的無用調(diào)用
  process: function () {
    clearTimeout(this.timeoutId); // 先清除之前的延時琅摩,并在下面重新開始計算時間

    var that = this; // 我們需要保存作用域,因為下面的setTimeout的作用域是在window躁劣,調(diào)用不要我們需要執(zhí)行的this.performProcessiong方法
    this.timeoutId = setTimeout(function () { // 100毫秒以后執(zhí)行performProcessiong方法
      that.performProcessiong();
    }, 100) // 如果還沒有執(zhí)行就又被觸發(fā)迫吐,會根據(jù)上面的clearTimeout來清除并重新開始計算
  }
};

// 嘗試開始執(zhí)行
processor.process(); // 需要重新綁定在一個觸發(fā)條件里

上面這段代碼就是最基本的實現(xiàn)方式,包在一個對象中账忘,然后在對象中互相調(diào)用志膀,里面的注釋應(yīng)該可以很清楚的說明每一步是干什么呢,最下面的processor.process()我們在實際使用的時候肯定是需要綁定在一個觸發(fā)條件上的鳖擒,比如之前的上電梯問題上溉浙,我們就需要把processor.process()方法綁定在增加人數(shù)的里面,這樣才會有多次調(diào)用的情況發(fā)生

上面再怎么說都是很簡單的實現(xiàn)蒋荚,在實際生產(chǎn)環(huán)境中戳稽,邏輯會相對復(fù)雜很多,但是萬變不離其宗期升,參透了最基礎(chǔ)的惊奇,再舉一反三就不是什么問題了

應(yīng)該叫“前搖”?播赁?

具體我也不知道應(yīng)該叫啥颂郎,英文叫“Leading edge”,甭管中文叫啥了容为,知道是什么意思就行了乓序。之前我們寫的代碼很明顯可以看出來,在我們連續(xù)觸發(fā)一個方法的時候坎背,是在setTimeout結(jié)束后才去真正執(zhí)行替劈,但是還有一種情況,那就是我們在連續(xù)觸發(fā)一個方法的時候得滤,第一次觸發(fā)就執(zhí)行了陨献,然后后面的連續(xù)觸發(fā)不再執(zhí)行,等連續(xù)觸發(fā)停止耿戚,經(jīng)過延時以后湿故,再次觸發(fā)才會真正執(zhí)行阿趁。

我還是盜圖吧膜蛔。坛猪。。普遍的形式是下面這種

image

連續(xù)觸發(fā)結(jié)束時執(zhí)行皂股,而我們現(xiàn)在說的“前搖”則是下面這種情況

image

在連續(xù)觸發(fā)的一開始就執(zhí)行了墅茉,然后往后的連續(xù)觸發(fā)不執(zhí)行,連續(xù)觸發(fā)停止后再經(jīng)過延時時間后觸發(fā)才會再次執(zhí)行

下面是我自己寫的呜呐,大概意思是這樣就斤,代碼實現(xiàn)也貼出來

image
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>電梯上人</title>
  <style>

  </style>
</head>
<body>
  <button id="addBtn">電梯上人,人數(shù)+1</button><button id="resetBtn">重置</button>
  <p id="personNum">電梯人數(shù):0(假設(shè)電梯可以無限裝人)</p>
  <script>
    var personNum = 0; // 電梯人數(shù)
    var okNext = true; // 是否可進(jìn)行下次執(zhí)行
    var timeoutFn = null;
    var addBtn = document.getElementById('addBtn'); // 獲取添加人數(shù)按鈕
    var personNumP = document.getElementById('personNum'); // 獲取顯示人數(shù)的標(biāo)簽
    var resetBtn = document.getElementById('resetBtn'); // 獲取重置按鈕
    /**
     * @method 電梯添加人數(shù)
     * @description 電梯可以上人蘑辑,但是上人以后就不能再上了洋机,不管怎么觸發(fā)都不行,除非停止觸發(fā)500毫秒以后洋魂,再觸發(fā)的時候才可以繼續(xù)執(zhí)行
     */
    function addPerson() {
      if (okNext) {
        okNext = false;
        personNum ++
        personNumP.innerHTML = `電梯人數(shù):${personNum}(假設(shè)電梯可以無限裝人)`
      }
      clearTimeout(timeoutFn);
      timeoutFn = setTimeout(function () {
        okNext = true;
      }, 500)
    }
    /**
     * @method 重置
     */
    function reset() {
      personNum = 0;
      personNumP.innerHTML = '電梯人數(shù):0(假設(shè)電梯可以無限裝人)';
    }

    addBtn.addEventListener('click', addPerson);
    resetBtn.addEventListener('click', reset);
  </script>
</body>
</html>

上面代碼要是看不太明白绷旗,可以直接粘下去自己執(zhí)行以下看看是什么感覺,就知道是什么意思了副砍。

代碼純我自己寫的衔肢,要是有不對的地方,請大佬指正啊

Throttle 節(jié)流

什么是節(jié)流

節(jié)流呢豁翎,也是我自己的理解角骤,在連續(xù)觸發(fā)一個方法的某一時間段中,控制方法的執(zhí)行次數(shù)心剥。

同樣舉個例子吧邦尊,一個地鐵進(jìn)站閘口,10秒進(jìn)一個人(10秒內(nèi)執(zhí)行一個方法)优烧,管這10秒中來了是5個人蝉揍、10個人還是20個人,都只是進(jìn)一個人(從第一次觸發(fā)后10秒不管被觸發(fā)多少次都不會執(zhí)行匙隔,直到下一個10秒才會再執(zhí)行)疑苫。

如何實現(xiàn)呢?纷责?

時間戳

我們首先用時間戳來判斷前后的時間間隔捍掺,然后就可以知道我從上次執(zhí)行完這個方法過了多久,過了這么長時間再膳,是不是已經(jīng)超過了自己規(guī)定的時長挺勿,如果時長超過了,我就可以再次執(zhí)行了

image
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>地鐵進(jìn)站</title>
</head>
<body>
  <button id="addBtn">進(jìn)站人數(shù)+1</button><button id="resetBtn">重置</button>
  <p id="personTotal">旅客總?cè)藬?shù):0</p>
  <p id="personNum">進(jìn)站人數(shù):0</p>
  <script>
    var personNum = 0; // 進(jìn)站人數(shù)
    var personTotal = 0; // 一共來了多少人
    var addBtn = document.getElementById('addBtn'); // 獲取添加人數(shù)按鈕
    var personNumP = document.getElementById('personNum'); // 獲取顯示人數(shù)的標(biāo)簽
    var personTotalP = document.getElementById('personTotal'); // 獲取顯示總?cè)藬?shù)的標(biāo)簽
    var resetBtn = document.getElementById('resetBtn'); // 獲取重置按鈕
    /**
     * @method 增加進(jìn)站人數(shù)
     * @description 每個時間間隔執(zhí)行的方法
     */
    function addPerson() {
      personNum ++;
      personNumP.innerHTML = `進(jìn)站人數(shù):${personNum}`;
    }
    /**
     * @method 節(jié)流方法(時間戳)
     * @param {Function} fn 需要節(jié)流的實際方法
     * @param {Number} wait 需要控制的時間長度
     * @description 根據(jù)上一次執(zhí)行的時間喂柒,和這一次執(zhí)行的時間做比較不瓶,如果大于控制的時間禾嫉,就可以執(zhí)行
     */
    function throttle(fn, wait) {
      var prev = 0; // 第一次執(zhí)行的時候是0,所以第一次點擊的時候肯定大于這個數(shù)蚊丐,所以會立馬執(zhí)行
      return function () {
        var context = this;
        var args = arguments;
        var now = Date.now(); // 實際執(zhí)行的時間
        personTotal ++;
        personTotalP.innerHTML = `旅客總?cè)藬?shù):${personTotal}`;
        if (now - prev >= wait) { // 執(zhí)行的時間是不是比上次執(zhí)行的時間大于需要延遲的時間熙参,大于,我們就執(zhí)行
          fn.apply(context, args);
          prev = now; // 執(zhí)行了以后麦备,重置上一次執(zhí)行的時間為剛剛執(zhí)行這次函數(shù)的時間孽椰,下次執(zhí)行就用這個時間為基準(zhǔn)
        }
      }
    }
    /**
     * @method 重置
     */
    function reset() {
      personNum = 0;
      personTotal = 0;
      personNumP.innerHTML = '進(jìn)站人數(shù):0';
      personTotalP.innerHTML = `旅客總?cè)藬?shù):0`;
    }

    addBtn.addEventListener('click', throttle(addPerson, 1000));
    resetBtn.addEventListener('click', reset);
  </script>
</body>
</html>

節(jié)流函數(shù)throttle用到了作用域,call凛篙、apply和閉包等相關(guān)的知識黍匾,看不懂的可以看我之前的文章

  1. 《前端戰(zhàn)五渣學(xué)JavaScript——閉包》
  2. 《前端戰(zhàn)五渣學(xué)JavaScript——call、apply以及bind》

上面的代碼中我感覺可以很直觀的看出來是根據(jù)判斷前后兩次的時間呛梆,來得知可不可以進(jìn)行下一次函數(shù)的執(zhí)行锐涯。參考著代碼中的注釋我覺得應(yīng)該可以看明白吧??????

setTimeout

如果我們用setTimeout的話,我們只需要更改一下throttle方法

image
/**
 * @method 節(jié)流方法(setTimeout)
 * @param {Function} fn 需要節(jié)流的實際方法
 * @param {Number} wait 需要控制的時間長度
 * @description 這個方法就很類似防抖了填物,就是判斷當(dāng)前函數(shù)有沒有延遲setTimeout函數(shù)纹腌,有的話就不執(zhí)行了
 */
function throttle(fn, wait) {
  var timeout = null; 
  return function () {
    var context = this;
    var args = arguments;
    personTotal ++;
    personTotalP.innerHTML = `旅客總?cè)藬?shù):${personTotal}`;
    if (!timeout) { 
      var that = this;
      timeout = setTimeout(() => {
        timeout = null;
        fn.apply(context, args)
      }, wait)
    }
  }
}

雖然我們只需要更改幾行代碼就實現(xiàn)了用setTimeout實現(xiàn)節(jié)流的這個方法,但是我們仔細(xì)看上面的圖融痛,我們可以發(fā)現(xiàn)壶笼,當(dāng)我點擊第一次的時候,進(jìn)站旅客是沒有增加的雁刷,這跟我們實際情況不一樣覆劈,我們先來的,我不用等啊沛励,我直接就能進(jìn)站责语,對不對。還有當(dāng)我結(jié)束增加人數(shù)的時候目派,進(jìn)站旅客過去等待時間以后還會加一個人坤候,這當(dāng)然也不是我們想看到的。

使用時間戳還是setTimeout企蹭,取決于業(yè)務(wù)場景了

rAF(requestAnimationFrame)

誒白筹??rAF是什么谅摄?什么是requestAnimationFrame徒河?這在我沒有寫這篇博客的時候,我根本不知道window下還有個這個方法送漠,神奇吧顽照,那這個方法是干什么的呢?闽寡?

告訴瀏覽器——你希望執(zhí)行一個動畫代兵,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動畫尼酿。該方法需要傳入一個回調(diào)函數(shù)作為參數(shù),該回調(diào)函數(shù)會在瀏覽器下一次重繪之前執(zhí)行植影∩亚妫————《MDN Web Docs》

就是在用這個可以一直重繪動畫,然后讓人看起來是個動畫何乎,重繪的這個過程是個很頻繁的操作句惯,所以如果我們自己寫土辩,不加以干涉支救,在性能和資源上會造成嚴(yán)重的浪費(fèi),所以我們可以使用requestAnimationFrame來使用我們的動畫看起來很流暢拷淘,又不會頻繁調(diào)用

優(yōu)點

  1. 目標(biāo)是60fps(16毫秒的一幀)各墨,瀏覽器將決定如何安排渲染的最佳時間。
  2. 相對簡單和標(biāo)準(zhǔn)的API启涯,未來不會改變贬堵,減少維護(hù)成本。

缺點

  1. rAF是內(nèi)部api结洼,所以我們并不方便修改
  2. 如果瀏覽器選項卡沒有激活黎做,就用不了
  3. 兼容性不好,在IE9松忍,Opera Mini和舊Android中仍然不支持
  4. node中不能使用

讓我們來使用rAF吧

直接上圖

image
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>rAF使用</title>
  <style>
    #SomeElementYouWantToAnimate {
      width: 100px;
      height: 100px;
      background-color: #000;
    }
  </style>
</head>
<body>
  <div id="SomeElementYouWantToAnimate"></div>
  <script>
    var start = null;
    var element = document.getElementById('SomeElementYouWantToAnimate');
    element.style.position = 'absolute';
    /**
     * @method 移動我們的小黑方塊
     */
    function step(timestamp) {
      if (!start) start = timestamp;
      var progress = timestamp - start;
      element.style.left = Math.min(progress / 10, 200) + 'px';
      if (progress < 2000) {
        window.requestAnimationFrame(step);
      }
    }

    window.requestAnimationFrame(step);
  </script>
</body>
</html>

總結(jié)

rAF是一個內(nèi)部api蒸殿,固定的16毫秒執(zhí)行一次,因為人眼接受60fps的動畫就會感到很流暢了鸣峭,如果我們需要改變rAF的執(zhí)行時間宏所,那我們只能自己去寫動畫的方法,節(jié)流還是防抖摊溶,看個人愛好了

收官

防抖:連續(xù)觸發(fā)一個函數(shù)爬骤,不管是觸發(fā)開始執(zhí)行還是結(jié)束執(zhí)行,只要在連續(xù)觸發(fā)莫换,就只執(zhí)行一次

節(jié)流:規(guī)定時間內(nèi)只執(zhí)行一次霞玄,不管是規(guī)定時間內(nèi)被觸發(fā)了多少次

rAF:也算是一種節(jié)流手段,原生api拉岁,旨在使動畫在盡量少占用資源的情況下使動畫流暢

End Game

《復(fù)仇者聯(lián)盟4》現(xiàn)階段的漫威宇宙的結(jié)束坷剧,《哈利·波特》《火影忍者》一個個完結(jié)的電影,雖然在時刻提醒著我們青春再慢慢的消失膛薛,正如英雄聯(lián)盟中的那句話听隐,我們有了新的敵人叫“生活”。當(dāng)這些完結(jié)的并不是真正的結(jié)束哄啄,《哈利·波特》有《神奇動物在哪里》雅任,《火影忍者》有《博人傳》风范,《鋼鐵俠》有《蜘蛛俠》,晚輩從前輩手中接過接力棒沪么,繼續(xù)往后跑硼婿,我們也從自己青蔥的歲月進(jìn)入下一階段,努力奮斗吧G莩怠寇漫!

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市殉摔,隨后出現(xiàn)的幾起案子州胳,更是在濱河造成了極大的恐慌,老刑警劉巖逸月,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栓撞,死亡現(xiàn)場離奇詭異,居然都是意外死亡碗硬,警方通過查閱死者的電腦和手機(jī)瓤湘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恩尾,“玉大人弛说,你說我怎么就攤上這事『惨猓” “怎么了木人?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猎物。 經(jīng)常有香客問我虎囚,道長,這世上最難降的妖魔是什么蔫磨? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任淘讥,我火速辦了婚禮,結(jié)果婚禮上堤如,老公的妹妹穿的比我還像新娘蒲列。我一直安慰自己,他們只是感情好搀罢,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布蝗岖。 她就那樣靜靜地躺著,像睡著了一般榔至。 火紅的嫁衣襯著肌膚如雪抵赢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音铅鲤,去河邊找鬼划提。 笑死,一個胖子當(dāng)著我的面吹牛邢享,可吹牛的內(nèi)容都是我干的鹏往。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骇塘,長吁一口氣:“原來是場噩夢啊……” “哼伊履!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起款违,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤唐瀑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后奠货,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體介褥,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年递惋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溢陪。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡萍虽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出形真,到底是詐尸還是另有隱情杉编,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布咆霜,位于F島的核電站邓馒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蛾坯。R本人自食惡果不足惜光酣,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脉课。 院中可真熱鬧救军,春花似錦、人聲如沸倘零。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呈驶。三九已至拷泽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背司致。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工订晌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚌吸。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓锈拨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羹唠。 傳聞我的和親對象是個殘疾皇子奕枢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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