Promise

為什么需要引入 Promise

我們都知道web 單線程 有很多異步回調,這短短的一段代碼里面竟然出現(xiàn)了五次回調露戒,這么多的回調會導致代碼的邏輯不連貫畔勤、不線性峦甩,非常不符合人的直覺习寸,這就是異步回調影響到我們的編碼方式乘盖。


//執(zhí)行狀態(tài)
function onResolve(response){console.log(response) }
function onReject(error){console.log(error) }

let xhr = new XMLHttpRequest()
xhr.ontimeout = function(e) { onReject(e)}
xhr.onerror = function(e) { onReject(e) }
xhr.onreadystatechange = function () { onResolve(xhr.response) }

//設置請求類型射赛,請求URL副签,是否同步信息
let URL = 'https://time.geekbang.com'
xhr.open('Get', URL, true);

//設置參數
xhr.timeout = 3000 //設置xhr請求的超時時間
xhr.responseType = "text" //設置響應返回的數據格式
xhr.setRequestHeader("X_TEST","time.geekbang")

//發(fā)出請求
xhr.send();

那么怎么才能 變的更加的線性山析,我們開始封裝異步回調堰燎,只在乎輸入和輸出的結果。

引入promise 是如何解決消滅嵌套調用和多次錯誤處理盖腿?
Promise 如何實現(xiàn)了回調函數的延時綁定爽待?
如何將回調函數 onResolve 的返回值穿透到最外層,擺脫嵌套循環(huán)的翩腐?
Promise 出錯后鸟款,是怎么通過“冒泡”傳遞給最后那個捕獲異常的函數?
Promise 中為什么要引入微任務茂卦?

promise

  • 1何什、對象的狀態(tài)不受外界影響。Promise對象代表一個異步操作等龙,有三種狀態(tài):pending(進行中)处渣、fulfilled(已成功)和rejected(已失敗)
  • 2蛛砰、一旦狀態(tài)改變罐栈,就不會再變,任何時候都可以得到這個結果泥畅。Promise對象的狀態(tài)改變荠诬,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

  • Promise實例生成以后位仁,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數柑贞。
  • resolved 函數是,promise 對象從pending 變?yōu)?resolved聂抢,在異步操作成功時調用钧嘶,并將異步操作的結果,作為參數傳遞出去琳疏。
  • rejected 函數是有决,promise 對象從pending 變?yōu)?rejected,在異步操作失敗時調用空盼,并將異步操作報出的錯誤疮薇,作為參數傳遞出去。
  • Promise實例生成以后我注,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數。
promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

第一個回調函數是Promise對象的狀態(tài)變?yōu)閞esolved時調用迟隅,
第二個回調函數是Promise對象的狀態(tài)變?yōu)閞ejected時調用但骨。
其中励七,第二個函數是可選的,不一定要提供奔缠。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved
// promise 是立即執(zhí)行的掠抬,promise狀態(tài)進入resolve 狀態(tài),
//則直接將回調放入微任務隊列中校哎,執(zhí)行then 方法是同步的两波,
//但是then 中的回調是異步的

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1
// 調用resolve或reject并不會終結 Promise 的參數函數的執(zhí)行。
//調用resolve(1)以后闷哆,后面的console.log(2)還是會執(zhí)行腰奋,并且會首先打印出來。

Promise.prototype.then()

Promise 實例具有then方法抱怔,也就是說劣坊,then方法是定義在原型對象。

  • then方法的第一個參數是resolved狀態(tài)的回調函數屈留,
  • 第二個參數(可選)是rejected狀態(tài)的回調函數局冰。
  • then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的別名灌危,用于指定發(fā)生錯誤時的回調函數康二。

const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

Promise 對象的錯誤具有“冒泡”性質,會一直向后傳遞勇蝙,直到被捕獲為止沫勿。也就是說,錯誤總是會被下一個catch語句捕獲浅蚪。

  • catch 返回的仍然是一個promise藕帜,后面還可以調用then ,如果catch 中間不拋出錯誤惜傲,就直接跳過洽故。

Promise.prototype.finally()

不管promise最后的狀態(tài),在執(zhí)行完then或catch指定的回調函數以后盗誊,都會執(zhí)行finally方法指定的回調函數

finally方法的回調函數不接受任何參數时甚,這意味著沒有辦法知道,前面的 Promise 狀態(tài)到底是fulfilled還是rejected哈踱。這表明荒适,finally方法里面的操作,應該是與狀態(tài)無關的开镣,不依賴于 Promise 的執(zhí)行結果刀诬。

Promise.all()

Promise.all()方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例邪财。

const p = Promise.all([p1, p2, p3]);

  • 只有p1陕壹、p2质欲、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成fulfilled糠馆,此時p1嘶伟、p2、p3的返回值組成一個數組又碌,傳遞給p的回調函數九昧。

  • 只要p1、p2毕匀、p3之中有一個被rejected铸鹰,p的狀態(tài)就變成rejected,此時第一個被reject的實例的返回值期揪,會傳遞給p的回調函數掉奄。

實現(xiàn)一個promise.all
有時候面試會遇到這樣的問題

  • 首先我們要知道 promise.all 返回的是一個promise 實例

  • 如果傳入的參數中的 promise 都變成完成狀態(tài),Promise.all 返回的 promise 異步地變?yōu)橥瓿伞?/p>

  • 如果傳入的參數中凤薛,有一個 promise 失敗姓建,Promise.all 異步地將失敗的那個結果給失敗狀態(tài)的回調函數,而不管其它 promise 是否完成

  • 在任何情況下缤苫,Promise.all 返回的 promise 的完成狀態(tài)的結果都是一個數組

  Promise.all = function (promises){
        return new Promise((resolve,reject) => {
          // 將迭代對象轉化為數組
          promises = Array.from(promises)
          if(promises.length === 0){
            resolve([]) 
          }else{
            let result = [];
            let index = 0;
            for( let i = 0; i < promises.length; i++){
              Promise.resolve(promises[i]).then(data=>{
                result[i] = data;
                if(++index === promises.length){
                  resolve(result)
                }
              },err =>{
                reject(err)
                return          
                })
            }
          }
        })
      }
// 封裝 Promise.all方法
Promise.all = function (values) {
    return new Promise((resolve, reject) => {
        let result = []; // 存放返回值
        let counter = 0; // 計數器速兔,用于判斷異步完成
        function processData(key, value) {
            result[key] = value;
            // 每成功一次計數器就會加1,直到所有都成功的時候會與values長度一致活玲,則認定為都成功了涣狗,所以能避免異步問題
            if (++counter === values.length) {
                resolve(result);
            }
        }
        // 遍歷 數組中的每一項,判斷傳入的是否是promise
        for (let i = 0; i < values.length; i++) {
            let current = values[i];
            // 如果是promise則調用獲取data值舒憾,然后再處理data
            if (isPromise(current)) {
                current.then(data => {
                    processData(i, data);
                }, reject);
            } else {
                // 如果不是promise镀钓,傳入的是普通值,則直接返回
                processData(i, current);
            }
        }
    });
}

promise 核心原理解析:

Promise函數參數可以作為輸入信息镀迂,而后經過Promise的內部處理

// 實例化 Promise
new Promise((resolve, reject)=> {
    // 輸入
    AjaxRequest.post({
        url: 'url',
        data: {},
        sueccess: ()=> {
            // resolve
            resolve(res)
        },
        fail: (err)=> {
            // reject
            reject(err)
        }
    })
}).then((res)=> {
    // res 輸出
    // ...操作
}).catch((err)=> {
    // err 輸出
    // ...操作
})

內部進行了哪些操作呢丁溅?

pending狀態(tài)下會運行的函數

1、實例化構造函數

// 首先運行探遵,Promise構造函數
function Promise(fn) {
    if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
    // _deferreds的類型窟赏,1是 single,2是 array
    this._deferredState = 0;
    // 0 - pending
    // 1 - fulfilled(resolved)
    // 2 - rejected
    // 3 - 另一個Promise的狀態(tài)
    this._state = 0;
    // promise 執(zhí)行結果
    this._value = null;
    // then注冊回調數組
    this._deferreds = null;
    // fn等于noop 即return
    if (fn === noop) return;
    // 接受Promise回調函數 和 this 作為參數
    doResolve(fn, this);
}

Promise構造函數箱季,會初始化屬性涯穷,fn就是我們傳入的函數。
doResolve(fn, this);藏雏,this指向它自己拷况,負責執(zhí)行fn函數。
等下面的then函數和catch函數的回調函數注冊完之后,doResolve函數將立即執(zhí)行

2赚瘦、then 方法注冊回調函數

Promise.prototype.then = function(onFulfilled, onRejected) {
    if (this.constructor !== Promise) {
        // safeThen函數也是通過調用handle函數最疆,return 新的Promise對象
        return safeThen(this, onFulfilled, onRejected);
    }
    // 生成新的Promise對象
    var res = new Promise(noop);
    handle(this, new Handler(onFulfilled, onRejected, res));
    return res;
};

function safeThen(self, onFulfilled, onRejected) {
  return new self.constructor(function (resolve, reject) {
    var res = new Promise(noop);
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}


// Handler構造函數
// 它的作用是掛載 then中的回調函數 和 一個空的Promise對象
function Handler(onFulfilled, onRejected, promise){
    // then中的Fulfilled回調函數
    this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
    // then中的Rejected回調函數
    this.onRejected = typeof onRejected === 'function' ? onRejected : null;
    // 保存新的Promise
    this.promise = promise;
}

// 保存then注冊回調函數,更新回調函數狀態(tài)
function handle(self, deferred) {
      while (self._state === 3) {
       self = self._value;
     }
    if (Promise._onHandle) {
      Promise._onHandle(self);
    }

    // pedding 狀態(tài) 
    if (self._state === 0) {
        // deferred == new Handler(onFulfilled, onRejected, res)
        if (self._deferredState === 0) {
            self._deferredState = 1;
            // 存儲then回調deferred對象
            self._deferreds = deferred;
            return;
        }
        if (self._deferredState === 1) {
            self._deferredState = 2;
            // 存儲then回調deferred對象
            self._deferreds = [self._deferreds, deferred];
            return;
        }
        // 存儲then回調函數對象
        self._deferreds.push(deferred);
        return;
    }

    // 只有當進入到非pedding狀態(tài)蚤告,handleResolved才會運行
    handleResolved(self, deferred);
}

Handler函數生成一個deffer對象,用于保存then函數中的onFulfilled和onRejected回調.以及返回的新的promise實例服爷。
then方法中的核心函數就是handle函數杜恰,它負責接收this和new Handler對象。
若在pedding狀態(tài)下仍源,handle函數只負責注冊回調函數心褐,更新回調函數狀態(tài)。在非pedding狀態(tài)下笼踩,則會執(zhí)行handleResolved函數逗爹。

3、 catch方法注冊回調函數

Promise.prototype['catch'] = function (onRejected) {
  return this.then(null, onRejected);
};
// catch方法的回調函數實際是通過then方法來完成保存的嚎于。

4掘而、調用doResolve函數執(zhí)行fn

// 調用doResolve函數
function doResolve(fn, promise) {
    var done = false;
    
    // tryCallTwo函數執(zhí)行 類似于
    // (resolve, reject) => {if(err){reject(err);return};resolve(res)}執(zhí)行;
    var res = tryCallTwo(fn, function (value) {
        if (done) return;
        done = true;
        resolve(promise, value);
    }, function (reason) {
        if (done) return;
        done = true;
        reject(promise, reason);
    });

    // fn函數調用失敗,手動運行reject函數
    if (!done && res === IS_ERROR) {
        done = true;
        reject(promise, LAST_ERROR);
    }
}

doResolve是同步直接調用傳入的函數于购。
其中tryCallTwo函數作用是調用函數fn袍睡,它接受三個參數。先執(zhí)行fn函數肋僧,根據結果斑胜,再執(zhí)行resolve函數或reject函數。
在resolve函數或reject函數被調用之前嫌吠,Promise對象的狀態(tài)依然是pending止潘。

promise.png

進入resolve或reject狀態(tài)時會運行的函數:

調用resolve

若Promise對象的fn函數執(zhí)行正常,之后就會調用resolve函數


function resolve(self, newValue) {
    // 辫诅。凭戴。。省略
    
    // newValue存在 & (newValue是一個對象 || newValue是一個函數)
    if (
        newValue &&
        (typeof newValue === 'object' || typeof newValue === 'function')
    ) {
        // 獲取then函數
        var then = getThen(newValue);
        // 泥栖。簇宽。。省略

        if (
            then === self.then &&
            newValue instanceof Promise
        ) {
            // 如果newValue 是一個Promise對象吧享,那么調用finale函數
            self._state = 3;
            self._value = newValue;
            finale(self);
            return;
        } else if (typeof then === 'function') {
            // 如果newValue 是一個函數魏割,就繼續(xù)調用doResolve函數
            doResolve(then.bind(newValue), self);
            return;
        }
    }
    // 標記完成,進入結束流程
    self._state = 1;
    self._value = newValue;
    finale(self);
}

確認newValue的值钢颂,如果newValue是一個函數钞它,就繼續(xù)循環(huán)調用doResolve函數;
如果newValue 是一個Promise對象,那么就直接調用finale函數遭垛。
都不是尼桶,則直接調用finale函數。

調用finale函數

function finale(self) {
    // 單個回調
    if (self._deferredState === 1) {
        // 執(zhí)行handle函數锯仪,實際是執(zhí)行handleResolved
        handle(self, self._deferreds);
        self._deferreds = null;
    }
    // 回調數組
    if (self._deferredState === 2) {
        for (var i = 0; i < self._deferreds.length; i++) {
            // 執(zhí)行handle函數泵督,實際是執(zhí)行handleResolved
            handle(self, self._deferreds[i]);
        }
        self._deferreds = null;
    }
}

finale函數表示進入結束流程,執(zhí)行handle函數庶喜。
同時在上面已經說到小腊,在非pedding狀態(tài)下,執(zhí)行handle函數久窟,實際會是執(zhí)行handleResolved函數秩冈。

調用handleResolved函數

var asap = require('asap/raw');

function handleResolved(self, deferred) {
    asap(function() {
        var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
        // 不存在 onFulfilled & onRejected
        // deferred.promise 只是一個空的Promise對象
        if (cb === null) {
            // 1 - fulfilled(resolved)
            if (self._state === 1) {
                resolve(deferred.promise, self._value);
            } else {
                reject(deferred.promise, self._value);
            }
            return;
        }
        // 執(zhí)行cb回調函數
        var ret = tryCallOne(cb, self._value);
        if (ret === IS_ERROR) {
            // 錯誤,報reject
            reject(deferred.promise, LAST_ERROR);
        } else {
            resolve(deferred.promise, ret);
        }
    });
}

通過異步asap調用斥扛,若不存在onFulfilledonRejected入问,直接調用resolvereject。若存在稀颁,則tryCallOne回調的結果芬失,直接調用resolvereject

WechatIMG549.png

Promise 的注冊和執(zhí)行過程

第一道題

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    return new Promise((resolve, reject) => {
      console.log("內部promise");
      resolve();
    })
    .then(() => {
    console.log("內部第一個then");
    })
    .then(() => {
    console.log("內部第二個then");
    });
  })
  .then(() => {
    console.log("外部第二個then");
  });

//  當執(zhí)行 then 方法時峻村,如果前面的 promise 已經是 resolved 狀態(tài)麸折,
// 則直接將回調放入微任務隊列中

output:
外部promise
外部第一個then
內部promise
內部第一個then
內部第二個then
外部第二個then

  • 外部第一個 new Promise 執(zhí)行,執(zhí)行完 resolve ,所以立即將回調放入微任務隊列粘昨。所以此時 外部第一個then 放入微任務

  • 外部第一個 then 方法里面 return 一個 Promise垢啼,這個 return ,代表 外部的第二個 then 的執(zhí)行需要等待 return 之后的結果

  • 當然會先執(zhí)行完內部兩個 then 之后张肾,再執(zhí)行 外部的第二個 then

如果前面的 promise 已經是 resolved 狀態(tài)芭析,則會立即將回調推入微任務隊列(但是執(zhí)行回調還是要等到所有同步任務都結束后)

如果 then 中的回調返回了一個 promise,那么 then 返回的 promise 會等待這個 promise 被 resolve 后再 resolve

第二道題

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => {
      console.log("內部promise");
      resolve();
    })
      .then(() => {
        console.log("內部第一個then");
      })
      .then(() => {
        console.log("內部第二個then");
      });
  })
  .then(() => {
    console.log("外部第二個then");
  });

// 比上面的代碼少一個return

output:
外部promise
外部第一個then
內部promise
內部第一個then
外部第二個then
內部第二個then

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => {
      console.log("內部promise");
      resolve();
    })
      .then(() => {
        console.log("內部第一個then");
      })
      .then(() => {
        console.log("內部第二個then");
      }) .then(() => {
        console.log("內部第3個then");
      })
  })
  .then(() => {
    console.log("外部第二個then");
  })
 .then(() => {
    console.log("外部第3個then");
  })

外部promise
外部第一個then
內部promise
內部第一個then
外部第二個then
內部第二個then
外部第3個then
內部第3個then

事件執(zhí)行機制: 先注冊后執(zhí)行

*1吞瞪、 當new Promise 執(zhí)行碰到resolve 狀態(tài)確定之后馁启,開始第一個then 的微任務注冊。

  • 2芍秆、外1then 的回調還沒有執(zhí)行惯疙,是pending 狀態(tài)。所以外2then 的回調也不會被推入微任務隊列也不會執(zhí)行妖啥。(外部的第二個 then 的注冊霉颠,需要等待 外部的第一個 then 的同步代碼執(zhí)行完成

  • 3、在實例化時執(zhí)行函數荆虱,打印 log: 內部promise蒿偎,然后執(zhí)行 resolve 函數朽们,接著執(zhí)行到內部的第一個 then(內1then),由于前面的 promise 已被 resolve诉位,所以將回調放入微任務隊列中骑脱。

  • 4、內1then 返回的 promise 是 pending 狀態(tài) 時苍糠,內2then和外2 then 不注冊不執(zhí)行叁丧。

  • 5、外部1then 執(zhí)行完岳瞭,外1then 返回的 promise 的狀態(tài)由 pending 變?yōu)?resolved歹袁。同時遍歷之前通過 then 給這個 promise 注冊的所有回調,將它們的回調放入微任務隊列中寝优,也就是外2then 的回調

  • 外部的第一個 then 的同步操作已經完成了,然后開始注冊外部的第二個 then枫耳,此時外部的同步任務也都完成了乏矾。

  • 同步操作完成之后,那么開始執(zhí)行微任務:
    內部的第一個 then 是優(yōu)先于外部的第二個 then 的注冊迁杨,所以會執(zhí)行完內部的第一個 then 之后钻心;
    然后注冊內部的第二個 then ;
    然后執(zhí)行外部的第二個 then ;
    ,然后再執(zhí)行內部的第二個 then铅协。

第三道

如果調用resolve函數和reject函數時帶有參數, 參數會被傳遞給回調函數捷沸,resolve函數的參數除了正常的值以外,還可能是另一個 Promise 實例

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

這時p1的狀態(tài)就會傳遞給p2狐史,也就是說痒给,p1的狀態(tài)決定了p2的狀態(tài)。如果p1的狀態(tài)已經是resolved或者rejected骏全,那么p2的回調函數將會立刻執(zhí)行苍柏。

const p111 = new Promise(function (resolve, reject) {
  // ...
resolve()
}).then(()=>{
console.log('p1 then')
return 11
});

const p12 = new Promise(function (resolve, reject) {
  // ...
  resolve(p111);
}).then((p3)=>{
console.log('p2 then',p111,p3)
})

// p1 then   > p2 then Promise {<resolved>: 11} 11

改寫函數成promise 形式:

var fs = require("fs");
 
function myReadFile(){
    return new Promise(function(resolve,reject){
        fs.readFile("./index.html",function(err,data){
            if (!err) {
                resolve(data);
            }else{
                reject(err);
            }
        });
    });
}
 
myReadFile().then(function(d){
    console.log(d.toString());
}).catch();

紅燈3秒亮一次,綠燈1秒亮一次姜贡,黃燈2秒亮一次试吁;如何讓三個燈不斷交替重復亮燈?(用Promise實現(xiàn))三個亮燈函數已經存在:

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

紅燈3秒亮一次楼咳,綠燈1秒亮一次 熄捍,黃燈2秒亮一次,意思就是3秒執(zhí)行一次red函數母怜,2秒執(zhí)行一次green函數余耽,1秒執(zhí)行一次yellow函數,不斷交替重復亮燈糙申,意思就是按照這個順序一直執(zhí)行這3個函數宾添,這步可以利用遞歸來實現(xiàn)船惨。

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

var light = function (timmer, cb) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            cb();
            resolve();
        }, timmer);
    });
};

var step = function () {
    Promise.resolve().then(function () {
        return light(3000, red);
    }).then(function () {
        return light(2000, green);
    }).then(function () {
        return light(1000, yellow);
    }).then(function () {
        step();
    });
}

step();

https://es6.ruanyifeng.com/#docs/promise

http://www.reibang.com/p/4bb1521343ba

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缕陕,隨后出現(xiàn)的幾起案子粱锐,更是在濱河造成了極大的恐慌,老刑警劉巖扛邑,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怜浅,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔬崩,警方通過查閱死者的電腦和手機恶座,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沥阳,“玉大人跨琳,你說我怎么就攤上這事⊥┖保” “怎么了脉让?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長功炮。 經常有香客問我溅潜,道長,這世上最難降的妖魔是什么薪伏? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任滚澜,我火速辦了婚禮,結果婚禮上嫁怀,老公的妹妹穿的比我還像新娘设捐。我一直安慰自己,他們只是感情好塘淑,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布挡育。 她就那樣靜靜地躺著,像睡著了一般朴爬。 火紅的嫁衣襯著肌膚如雪即寒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天召噩,我揣著相機與錄音母赵,去河邊找鬼。 笑死具滴,一個胖子當著我的面吹牛凹嘲,可吹牛的內容都是我干的。 我是一名探鬼主播构韵,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼周蹭,長吁一口氣:“原來是場噩夢啊……” “哼趋艘!你這毒婦竟也來了?” 一聲冷哼從身側響起凶朗,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤瓷胧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棚愤,有當地人在樹林里發(fā)現(xiàn)了一具尸體搓萧,經...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年宛畦,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘸洛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡次和,死狀恐怖反肋,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情踏施,我是刑警寧澤囚玫,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站读规,受9級特大地震影響,放射性物質發(fā)生泄漏燃少。R本人自食惡果不足惜束亏,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阵具。 院中可真熱鬧碍遍,春花似錦、人聲如沸阳液。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帘皿。三九已至东跪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹰溜,已是汗流浹背虽填。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曹动,地道東北人斋日。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像墓陈,于是被迫代替她去往敵國和親恶守。 傳聞我的和親對象是個殘疾皇子第献,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內容

  • async 函數 含義 ES2017 標準引入了 async 函數,使得異步操作變得更加方便兔港。 async函數對 ...
    Xyaleo閱讀 1,089評論 0 4
  • 1. Promise 的含義 所謂Promise庸毫,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個...
    ROBIN2015閱讀 486評論 0 0
  • Promise 的含義 一句話概括一下promise的作用:可以將異步操作以同步操作的流程表達出來押框,避免了層層嵌套...
    雪萌萌萌閱讀 5,461評論 0 7
  • Promise 是異步編程的一種解決方案岔绸,比傳統(tǒng)的解決方案 —— 回調函數和事件 —— 更合理且強大 Promis...
    了凡和纖風閱讀 520評論 0 1
  • 都是名字惹的禍 自古以來,人們都把叫什么名字當做一件大事橡伞,并且對名字賦予了很多禮儀和祝愿盒揉。 早在先秦時期,《左傳》...
    山東田夫閱讀 2,805評論 28 68