面試 | JS 異步編程經(jīng)典面試題

原文地址

掘金

歡迎 GitHub star

大家好开缎,我是林一一棕叫,異步編程在 JS 中是無法避免的,也是面試必問的奕删。本文使用通俗易懂的語言解析異步編程中的原理俺泣,開始閱讀吧??

思維導(dǎo)圖

未命名文件.png

一、定時(shí)器

定時(shí)器:設(shè)定一個(gè)定時(shí)器完残,到了設(shè)定時(shí)間伏钠,瀏覽器會(huì)把對應(yīng)的方法執(zhí)行。每一個(gè)定時(shí)器執(zhí)行后都會(huì)有一個(gè)編號(hào)返回谨设,每個(gè)定時(shí)器編號(hào)不一樣熟掂。

1. 設(shè)定定時(shí)器

  • setTimeout([function], [interval])

function 都是在到達(dá)設(shè)定時(shí)間后才執(zhí)行。且執(zhí)行一次

let count = 1
let timer = setTimeout(function(){
    count++
    console.log(count)  // 2
}, 1000)
console.log(timer)  // 1
  • setInterval([function], [interval])

在設(shè)定時(shí)間內(nèi)執(zhí)行铝宵,不主動(dòng)停止的情況下一直執(zhí)行打掘。

let count = 1
let timer = setInterval(function(){
    count++
    console.log(count)  // 2
}, 1000)
console.log(timer)  // 1
/*
*   2
*   3
*   4
*   ...
*/

2. 清除定時(shí)器

clearTimeout/clearInterval 兩者都可以清除上面的兩種定時(shí)器。

  • 如何清除定時(shí)器鹏秋?

只需要定時(shí)器的返回值編號(hào)清除即可尊蚁。

let count = 1
let timer = setInterval(function(){
    count++
    console.log(count)
    // count == 3 ? clearTimeout(timer) : null
    count == 3 ? clearInterval(timer) : null
}, 1000)

二、異步編程的原理

先來看一個(gè)小例子

let a = 0
setTimeout(() =>{
    console.log('a', ++a)
}, 0)
console.log(a)
/* 輸出
*   0
*   1
*/

上面的例子中侣夷,setTimeout 是異步的横朋,瀏覽器會(huì)將異步的代碼加入到任務(wù)隊(duì)列中,等到同步的代碼執(zhí)行完成后才執(zhí)行異步的代碼

1. 同步

JS 是單線程的百拓,代碼至上而下執(zhí)行時(shí)遇到同步的代碼需要先執(zhí)行完才可以進(jìn)行下一步任務(wù)琴锭。比如循環(huán)等

2. 異步

所有需要等待的任務(wù)都是異步的晰甚。遇到異步代碼時(shí),不需要等待而是直接異步任務(wù)放入任務(wù)隊(duì)列决帖,等到后面的任務(wù)完成后厕九,才會(huì)返回來執(zhí)行沒有完成異步的代碼。比如事件綁定地回,所有定時(shí)器扁远,ajax 的異步處理,部分回調(diào)函數(shù)刻像,瀏覽器的渲染過程等等畅买。

let a = 0
setTimeout(() =>{
    console.log('a', ++a)
}, 0)
console.log(a)
while(true){
}

上面的代碼死循環(huán)了,即使定時(shí)器的時(shí)間到了也不會(huì)執(zhí)行细睡。因?yàn)橥降拇a沒有執(zhí)行完一步就不會(huì)執(zhí)行谷羞。

三、promise

1.基本概念

Promise 只是一個(gè)管理異步編程的類溜徙,本身是同步湃缎。Promise 有三個(gè)狀態(tài) pending/fulfilled/rejected,三個(gè)狀態(tài)只有兩個(gè)狀態(tài)出現(xiàn)要么成功要么失敗萌京。new Promise()時(shí)必須要傳入回調(diào)函數(shù) executor雁歌,否則報(bào)錯(cuò)宏浩。其中回調(diào)函數(shù)中有兩個(gè)參數(shù) resolve, reject知残,這兩個(gè)參數(shù)可不寫。

  • pending :初始化狀態(tài)比庄,開始執(zhí)行異步的任務(wù)求妹,只要執(zhí)行 new,new Promise(()=>{})佳窑,promise 的狀態(tài)就會(huì)變成 pending
  • fulfilled:成功狀態(tài)制恍,執(zhí)行 resolve()
  • rejected:失敗狀態(tài), 執(zhí)行 rejected()神凑。
    先看一個(gè)小栗子净神。
new Promise(()=> {
    setTimeout(()=> {
        console.log(1)
    }, 0)
    console.log(2)
}).then()
console.log(3)
/* 輸出
*   2
*   3
*   1
*/

創(chuàng)建一個(gè)新的 Promise 的實(shí)例也就是 new 這個(gè)過程中會(huì)把 Promise 中 的函數(shù)先執(zhí)行(不清楚 new 創(chuàng)建實(shí)例的過程中發(fā)生了什么可以看看這篇 面試 | 你不得不懂得 JS 原型和原型鏈)。函數(shù)體內(nèi)有異步操作的仍會(huì)加入任務(wù)隊(duì)列溉委,等到同步執(zhí)行完成后才執(zhí)行異步任務(wù)鹃唯,比如函數(shù)體內(nèi)的 setTimeout 函數(shù)。所以輸出的結(jié)果就是 2瓣喊,3坡慌,1

再來看一個(gè)小栗子

const promise = new Promise((resolve, reject) => {
  resolve('success1')
  reject('error')
  resolve('success2')
})

promise.then((res) => {
    console.log('then: ', res)
}).catch((err) => {
    console.log('catch: ', err)
}
// then: success1

promise 的狀態(tài)只能改變一次藻三,最后的狀態(tài)不是 fulfilled 就是 rejected洪橘。也就是說同一個(gè) promise 中的resolve()/ reject()只能執(zhí)行一個(gè)且一次跪者。

2. promise 是怎么管理異步的

promise 參數(shù)的回調(diào)函數(shù)體內(nèi)接收兩個(gè)參數(shù) resolve/ reject,這兩個(gè)參數(shù)可以作為兩個(gè)回調(diào)函數(shù)熄求。

  1. resolve():是異步操作執(zhí)行成功后執(zhí)行渣玲,promise 的狀態(tài)變成了 fulfilled,可以提供返回值弟晚,在 .then()中第一個(gè)參數(shù)接收
  2. reject():異步操作執(zhí)行失敗后執(zhí)行柜蜈,promise 的狀態(tài)變成了 rejected,可以提供返回值指巡,在 .then() 中第二個(gè)參數(shù)接收
    resolve()reject() 中只能傳遞一個(gè)參數(shù)淑履。promise 的狀態(tài)發(fā)生改變后不會(huì)再變化。
    resolve() 和 reject() 是異步操作藻雪,執(zhí)行這兩個(gè)方法時(shí)秘噪,會(huì)先執(zhí)行 resolve/reject 下面的同步代碼,等到主任務(wù)為空時(shí)勉耀,再去調(diào)用 resolve/reject 把存放的方法執(zhí)行指煎。
    Promise 對象上有私有屬性Promise.resolve()/ Promise.reject()等。
    舉一個(gè)沒什么意義的小栗子
new Promise((resolve, reject)=> {
    setTimeout(()=> {
        console.log('林')
        resolve('ok')
        // reject('fail')
        console.log('一一')
    }, 0)
}).then( res => {
    console.log('status:', res)
}, res => {
    console.log('status:', res)
})
// 林 
// 一一 
// ok

上面的栗子直接看出 resolve/reject 是異步的便斥。

3. promise.then(onfulfilled, onrejected) / promise.catch()

  • promise.then(onfulfilled, onrejected)
  1. promise.then() 方法中有兩個(gè)參數(shù)至壤,分別對應(yīng)著 promise 的兩種不同的狀態(tài),fulfilled, rejected枢纠。對應(yīng)的狀態(tài)執(zhí)行對應(yīng)的方法像街。
  2. promise.then() 中的參數(shù)是函數(shù),如果傳遞的不是函數(shù)就會(huì)造成值穿透晋渺,也就是resolve()/reject() 的返回值會(huì).then()中接收镰绎。
  3. promise.then() 能夠鏈?zhǔn)降恼{(diào)用,能夠鏈?zhǔn)秸{(diào)用的原因不是.then() 方法中有return this木西,而是每一個(gè) .then() 方法中都會(huì)返回一個(gè)新的Promise 實(shí)例畴栖。
  • promise.catch()
  1. promise.catch()promise.then() 第二個(gè)參數(shù)的簡便寫法,也就是用來捕獲 reject() 執(zhí)行后的 rejected狀態(tài)八千。
  2. .catch()也可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用吗讶,原因和.then() 方法一樣都是返回了一個(gè)新的 promise

.then()/.catch() 中的返回值都不能是 promise自己本身的實(shí)例恋捆,因?yàn)闀?huì)造成死循環(huán)

熱身題

1.舉一個(gè)小栗子

Promise.resolve(1)
    .then((res) => {
        console.log(res)
        return 2
    }).catch(err => {
        console.log(err)
    }).then( res => {
        console.log(res)
    })
// 1 2

最終輸出 1 2,

2. 舉一個(gè)值穿透的小栗子

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)

// 等價(jià)于
// Promise.resolve(1)
//   .then(console.log)

3. then()/.catch() 內(nèi)不能返回自己本身的promise 實(shí)例照皆,舉一個(gè)栗子

let pro = Promise.resolve()
  .then(() => {
    console.log('promise', pro)
    return pro
  })
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

創(chuàng)建的promise 實(shí)例是pro,返回值就不能是pro, 否則會(huì)造成死循環(huán)。

5. Promise.all([promise1, promise2...])

Promise.all() 中需要等待參數(shù)中所有 promise 的狀態(tài)都成功才執(zhí)行回調(diào)的.then()鸠信,如果有一個(gè)是失敗的那么就執(zhí)行 .catch()纵寝。接收的參數(shù)是一個(gè)包含 promise 實(shí)例的數(shù)組,.all() 這個(gè)方法的返回值也是一個(gè)新的promise 實(shí)例。

  • 全部執(zhí)行成功回調(diào) .then() 接收到的就是一個(gè)數(shù)組
  • 如果有執(zhí)行失敗的 promise 狀態(tài)爽茴,回調(diào) .catch 中就會(huì)捕獲到執(zhí)行失敗的 promise葬凳,promise.all() 執(zhí)行結(jié)束。
var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
let pro =  Promise.all([p1, p2, p3])
  .then(res => {
      console.log(res)  //  [1, 2, 3]
  })
  .catch( err => {
      console.log(err)
  })
console.log(pro)    // Promise {<pending>}

全部執(zhí)行成功室奏,那么.then() 獲取到的值就是resolve() 的返回值數(shù)組火焰。

6. Promise.race()

.race() 的作用也是接收一組異步任務(wù),然后并行執(zhí)行異步任務(wù)胧沫,只保留取一個(gè)最快執(zhí)行完成的異步操作的結(jié)果昌简,其他的方法仍在執(zhí)行,不過執(zhí)行結(jié)果會(huì)被拋棄绒怨。

  • 接收的是一組數(shù)組纯赎,只獲取一個(gè)最快執(zhí)行完成 resolve()/rejected() 的返回值,返回值不是一個(gè)數(shù)組
var p1 = new Promise(function(resolve, reject) {
    setTimeout(reject, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, "two");
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
});

兩個(gè)都完成南蹂,但 p2 更快

7. Promise.finally()

.finally 方法也是返回一個(gè) Promise犬金,他在 Promise 結(jié)束的時(shí)候,無論結(jié)果為 resolved 還是 rejected六剥,都會(huì)執(zhí)行里面的回調(diào)函數(shù)晚顷。

let promise = new Promise((resolve, reject) => {
    reject('error')
}).then( res => {
    console.log('then', res)
    return res
}).catch( err => {
    console.log('catch', err)   // `catch error`
     return err
}).finally( () => {
    console.log('finally')  //'finally'
})

熱身題

熱身題1

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})
promise.then(() => {
  console.log(3)
})
console.log(4)
// 1, 2, 4, 3

因?yàn)?resolve() 是異步的,promise.then也是異步的疗疟,在沒有獲取到 resolve()fulfilled 狀態(tài)時(shí).then() 不會(huì)執(zhí)行该默。

熱身題2

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})

const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})
/* 輸出
* once
* success 1002
* success 1002
*/

promise.then() 即使有多個(gè),但是resolve()/reject()后的調(diào)用時(shí)同時(shí)執(zhí)行的策彤。所以同時(shí)輸出了 success 1002

三栓袖、async 和 await

先來看一個(gè)栗子

function fn(){
    return new Promise((resolve, reject) => {
        setTimeout( () => {
            Math.random() < 0.5 ? resolve('resolve 001') : reject('reject 002')
        }, 0)
    })
}

async function get() {
    let res = await fn()
    console.log(res)
    console.log(1212)
}
get()

1. async

  1. asyncawait 是 ES7 中增加來對 promise 操作的方法,是 ES7 系列提供的語法糖锅锨,await 不能單獨(dú)使用一定要結(jié)合 async 來使用叽赊。
  2. async 會(huì)返回一個(gè) promise 對象,async 函數(shù)調(diào)用不會(huì)造成代碼的阻塞

2. await

  1. await 是用來 等待獲取 一個(gè) promiseresolve/reject 的執(zhí)行結(jié)果必搞,像上面的 let res = await fn() 是先把 fn()執(zhí)行后,來獲取 resolve/reject 返回的結(jié)果囊咏,不過 await 后面也可以不跟著一個(gè) promise恕洲,但是這樣寫就沒有意義了。
  2. await 或 await fn() 這個(gè)操作不是同步的梅割,而是異步的霜第。await 下面的代碼不會(huì)執(zhí)行,而是移入到任務(wù)隊(duì)列等待區(qū)户辞,等到主棧中的其他任務(wù)完成且 fn() 中的 promise 將結(jié)果返回泌类,await 下面的代碼才可以重新回到主棧中執(zhí)行。await 可以使 promise 的操作更加像同步的代碼底燎。
  3. 如果 await 等到的獲取結(jié)果是 reject() 返回的刃榨,那么 await 下面的代碼弹砚,就不會(huì)再執(zhí)行,因?yàn)橐呀?jīng)報(bào)錯(cuò)了枢希。
    舉一個(gè)小栗子,說明 async/await 是語法糖
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
// 上面的代碼等價(jià)于 ==>
async function async1() {
    console.log('async1 start');
    Promise.resolve(async2()).then(() => {
        console.log('async1 end')
    })
}

思考

熱身1桌吃,await 是同步嗎?苞轿,求輸出的結(jié)果

console.log(1)
function fn(){
    return new Promise((resolve, reject) => {
        console.log(5)
        resolve('resolve 001')
        console.log(6)
    })
}

async function get() {
    console.log(2)
    let res = await fn()
    console.log(res)
    console.log(3)
}
get()
console.log(4)
//1, 2, 5, 6, 4, resolve 001, 3

await 是異步的同時(shí)會(huì)讓出線程茅诱,fn() 執(zhí)行后線程開始讓出,那么 await 的后面的代碼不會(huì)立即執(zhí)行會(huì)先到主棧的等待區(qū)搬卒,主棧中 console.log(4) 執(zhí)行后瑟俭,再回來執(zhí)行 await 處的代碼。

2. 熱身2契邀,求輸出結(jié)果

console.log(1)
async function get() {
    console.log(2)
    let res = await 200
    console.log(res)
    console.log(3)
}
get()
console.log(4)
// 1, 2, 4, 200, 3

根據(jù)上面一題 await 異步代碼的原因尔当,可以容易的分析出答案。同時(shí)說明 await 后面也可以跟著一個(gè)非 promise 的實(shí)例蹂安。

四椭迎、經(jīng)典面試題

1. promise 的優(yōu)缺點(diǎn)/為什么使用 promise?

  • 優(yōu)點(diǎn):promise 可以解決回調(diào)地獄田盈,promise 大大增強(qiáng)了嵌套函數(shù)的可讀性和可維護(hù)性畜号,
  • 缺點(diǎn):無法取消 Promise,錯(cuò)誤需要通過回調(diào)函數(shù)來捕獲允瞧;如果不設(shè)置回調(diào)函數(shù)简软,Promise 內(nèi)部拋出的錯(cuò)誤,不會(huì)反映到外部述暂;當(dāng)處于 pending(等待)狀態(tài)時(shí)痹升,無法得知目前進(jìn)展到哪一個(gè)階段,是剛剛開始還是即將完成

2. setTimeout畦韭、Promise疼蛾、Async/Await 的區(qū)別

  • setTimeout: setTimeout 的回調(diào)函數(shù)放到宏任務(wù)隊(duì)列里,等到執(zhí)行棧清空以后執(zhí)行
  • Promise: Promise 本身是同步的立即執(zhí)行函數(shù)艺配,當(dāng)在 executor 中執(zhí)行 resolve或者 reject 的時(shí)候察郁,此時(shí)是異步操作,會(huì)先執(zhí)行 then/catch 等转唉,當(dāng)主棧完成時(shí)皮钠,才會(huì)去調(diào)用 resolve/reject 方法中存放的方法。
  • async: async 函數(shù)返回一個(gè) Promise 對象赠法,當(dāng)函數(shù)執(zhí)行的時(shí)候麦轰,一旦遇到 await 就會(huì)先返回,等到觸發(fā)的異步操作完成,再執(zhí)行函數(shù)體內(nèi)后面的語句款侵∧┘觯可以理解為,是讓出了線程喳坠,跳出了 async 函數(shù)體鞠评。

3. 實(shí)現(xiàn)一個(gè) sleep 函數(shù),比如 sleep(1000) 意味著等待 1000 毫秒壕鹉。

function sleep1(time) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, time);
    })
}
sleep1(1000).then(() => console.log("sleep1"));

4. Promise 構(gòu)造函數(shù)是同步執(zhí)行還是異步執(zhí)行剃幌,那么 then 方法呢

Promise 是同步的,執(zhí)行 new promise(callback) 時(shí)回調(diào)函數(shù)callback 就會(huì)被立即執(zhí)行晾浴,then() 方法是異步的负乡。

const promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() => {
    console.log(3)
})
console.log(4)

1243,promise 構(gòu)造函數(shù)是同步執(zhí)行的脊凰,then 方法是異步執(zhí)行的

5. 介紹下 Promise.all 使用抖棘、原理實(shí)現(xiàn)及錯(cuò)誤處理

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

Promise.all 方法接受一個(gè)數(shù)組作為參數(shù),p1狸涌、p2切省、p3 都是 Promise 實(shí)例,如果不是帕胆,就會(huì)先調(diào)用下面講到的 Promise resolve 方法务豺,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例拨扶,再進(jìn)一步處理。(Promise.all 方法的參數(shù)可以不是數(shù)組住闯,但必須具有 Iterator 接口鲁驶,且返回的每個(gè)成員都是 Promise 實(shí)例没咙。)

5. 介紹下 Promise.all, Promise.race() 的區(qū)別

看上面的介紹

Promise 的各種 api 實(shí)現(xiàn)會(huì)在下一篇文章中實(shí)現(xiàn)秦驯。給個(gè)期待吧??

五掌动、參考

Promise 必知必會(huì)(十道題)

BAT前端經(jīng)典面試問題:史上最最最詳細(xì)的手寫Promise教程

MDN async/await

六、結(jié)束

感謝閱讀到這里记餐,如果著篇文章能對你有一點(diǎn)啟發(fā)或幫助的話歡迎 github star, 我是林一一,下次見驮樊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市剥扣,隨后出現(xiàn)的幾起案子巩剖,更是在濱河造成了極大的恐慌,老刑警劉巖钠怯,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異曙聂,居然都是意外死亡晦炊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來断国,“玉大人贤姆,你說我怎么就攤上這事∥瘸模” “怎么了霞捡?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長薄疚。 經(jīng)常有香客問我碧信,道長,這世上最難降的妖魔是什么街夭? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任砰碴,我火速辦了婚禮,結(jié)果婚禮上板丽,老公的妹妹穿的比我還像新娘呈枉。我一直安慰自己,他們只是感情好埃碱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布猖辫。 她就那樣靜靜地躺著,像睡著了一般砚殿。 火紅的嫁衣襯著肌膚如雪啃憎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天瓮具,我揣著相機(jī)與錄音荧飞,去河邊找鬼。 笑死名党,一個(gè)胖子當(dāng)著我的面吹牛叹阔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播传睹,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耳幢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了欧啤?” 一聲冷哼從身側(cè)響起睛藻,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎邢隧,沒想到半個(gè)月后店印,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倒慧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年按摘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了包券。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炫贤,死狀恐怖溅固,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兰珍,我是刑警寧澤侍郭,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站掠河,受9級(jí)特大地震影響亮元,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜口柳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一苹粟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跃闹,春花似錦嵌削、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至找默,卻和暖如春艇劫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惩激。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工店煞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人风钻。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓顷蟀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骡技。 傳聞我的和親對象是個(gè)殘疾皇子鸣个,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

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