Promise 完全解讀

目錄

  • 一. Promise 簡(jiǎn)介
    • Promise 是什么埂奈?
    • 我們?yōu)槭裁葱枰?Promise仰猖?
    • Promise 能解決什么扯罐?
    • Promise 的特點(diǎn)
    • Promise 的缺點(diǎn)
  • 二. Promise API 解析
    • Promise 的構(gòu)造方法
    • Promise 的實(shí)例方法
    • Promise 類(lèi)級(jí)別方法
  • 三. Promise 深度剖析
    • Promise 與 setTimeout
    • 多層級(jí) .then()

一. Promise 簡(jiǎn)介

1. Promise 是什么橄登?

ES6 出現(xiàn)的目標(biāo)是為了使 JavaScript 語(yǔ)言可以編寫(xiě)大型的復(fù)雜應(yīng)用程序轧膘,使之成為企業(yè)級(jí)的開(kāi)發(fā)語(yǔ)言熬荆,Promise 也是其中的一環(huán)舟山。

從語(yǔ)法上講 Promise 是個(gè)內(nèi)置對(duì)象,抽象來(lái)看卤恳,它像是一個(gè)容器累盗,里面保存著一個(gè)異步操作的執(zhí)行結(jié)果,Promise 提供了一套 API 以保證所有異步操作的統(tǒng)一處理方法突琳。

2. 我們?yōu)槭裁葱枰?Promise若债?

我們先來(lái)舉一個(gè)簡(jiǎn)單的 “栗子”,某人需要做三件事(A拆融,B蠢琳,C)啊终,并且要按照這個(gè)順序依次執(zhí)行,現(xiàn)在將這個(gè)轉(zhuǎn)換為傳統(tǒng)的代碼方式:

// 首先我們要先定義這三件事(A傲须,B蓝牲,C)分別為三個(gè)函數(shù)
// 這三個(gè)函數(shù)都需要提供一個(gè)回調(diào)來(lái)表示事情的結(jié)束
function A(callback) {
  console.log('Do A.');
  callback();
}

function B(callback) {
  console.log('Do B.');
  callback();
}

function C(callback) {
  console.log('Do C.');
  callback();
}

// 現(xiàn)在,如果我想要依次做這三件事我需要這樣泰讽。例衍。。
A(function() {
  // 其它的一些代碼
  B(function() {
    // 其它的一些代碼
    C(function() {
      // 其它的一些代碼
    });
  });
});

可以看出已卸,當(dāng)涉及到異步操作時(shí)佛玄,曾經(jīng)的大部分方式都是靠回調(diào)的嵌套來(lái)實(shí)現(xiàn)的,然而這樣的方式造成了幾個(gè)十分嚴(yán)重的問(wèn)題:

  • 出現(xiàn)了多層回調(diào)累澡,當(dāng)加上業(yè)務(wù)代碼后翎嫡,將會(huì)使整體顯得臃腫且凌亂。
  • 回調(diào)的出現(xiàn)導(dǎo)致邏輯的流程不清晰永乌,不具有可讀性和維護(hù)性惑申。
  • 當(dāng)嵌套層級(jí)過(guò)多時(shí)會(huì)產(chǎn)生大量無(wú)用數(shù)據(jù)的滯留以及數(shù)據(jù)的混雜。
  • 使用回調(diào)函數(shù)便完全浪費(fèi)了 return 和 throw 關(guān)鍵字的能力翅雏。

綜上所述圈驼,我們需要一種更好的解決辦法在某些(并不是全部)方面來(lái)取代回調(diào)(callback)方式的異步操作。

3. Promise 能解決什么望几?

  • 編寫(xiě)大型應(yīng)用時(shí)绩脆,一種高級(jí)、實(shí)用且能解決實(shí)際問(wèn)題的高大上語(yǔ)法橄抹。
  • 避免層層嵌套的回調(diào)函數(shù)靴迫,將異步操作以同步操作的流程表達(dá)出來(lái),使邏輯更加清晰楼誓。
  • Promise 提供統(tǒng)一的接口來(lái)進(jìn)行異步操作玉锌。

4. Promise 的特點(diǎn)

Promise 是基于狀態(tài)的,一個(gè) Promise 對(duì)象表示了一個(gè)異步操作疟羹,而這個(gè)操作會(huì)有三種狀態(tài):Pending(進(jìn)行中)主守、Resolved(已成功)和 Rejected(已失敗)榄融。只有異步操作的執(zhí)行結(jié)果可以決定是哪一種狀態(tài)参淫,任何其它操作都無(wú)法改變。而且愧杯,一旦狀態(tài)改變涎才,就不會(huì)再變化。

Promise 的異步操作不需要像回調(diào)一樣執(zhí)行異步操作后立即就會(huì)調(diào)用回調(diào)力九,Promise 允許任何時(shí)候都可以得到這個(gè)異步操作的結(jié)果耍铜。也就是說(shuō)它其實(shí)和事件的機(jī)制是完全不同的邑闺,事件觸發(fā)時(shí),如果你沒(méi)有處于監(jiān)聽(tīng)狀態(tài)业扒,那么錯(cuò)過(guò)了就再也得不到此次事件的結(jié)果检吆,而 Promise 則是將結(jié)果狀態(tài)會(huì)凝固舒萎,等待你去觀察這個(gè)異步操作的結(jié)果程储。

5. Promise 的缺點(diǎn)

一旦構(gòu)造了 Promise 實(shí)例就代表執(zhí)行了一個(gè)異步操作,也就是說(shuō)它會(huì)立即執(zhí)行臂寝,并且中途無(wú)法取消章鲤。

如果不設(shè)置回調(diào),Promise 內(nèi)部拋出的錯(cuò)誤咆贬,不會(huì)反應(yīng)到外部败徊。(有利有弊,具體看怎么用)

Promise 其實(shí)只適合單一的異步程序掏缎,并不適合不斷發(fā)生的事件處理皱蹦,所以使用時(shí),要找好最適合使用的場(chǎng)景眷蜈。

二. Promise API 解析

1. Promise 構(gòu)造方法

Promise 本身就是個(gè)構(gòu)造函數(shù)沪哺,用來(lái)生成 Promise 實(shí)例。

Promise 構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù)酌儒,而該函數(shù)的兩個(gè)參數(shù)分別為 resolve 和 reject辜妓,它們分別是兩個(gè)函數(shù),由 JavaScript 引擎提供忌怎。

resolve 函數(shù)的作用是將 Promise 對(duì)象的狀態(tài)從 Pending 變?yōu)?Resolved籍滴,在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去榴啸。

reject 函數(shù)的作用是將 Promise 對(duì)象的狀態(tài)從 Pending 變?yōu)?Rejected孽惰,在異步操作失敗時(shí)調(diào)用,并將異步操作失敗所拋出的錯(cuò)誤鸥印,作為參數(shù)傳遞出去灰瞻。

const promise = new Promise((resolve, reject) => {
  // 模擬一個(gè)異步操作
  setTimeout(function() {
    if ( /* 異步操作成功 */ ) {
      // 異步操作成功,攜帶載荷將狀態(tài)變?yōu)?resolved
      resolve(payload);
    } else {
      // 異步操作失敗辅甥,攜帶錯(cuò)誤將狀態(tài)變?yōu)?rejected
      reject(error);
    }
  }, 1000);
});

Promise 實(shí)例生成后酝润,異步操作就已經(jīng)開(kāi)始執(zhí)行了。

要注意璃弄,resolve 和 reject 的調(diào)用是對(duì) Promise 對(duì)象狀態(tài)的變更和數(shù)據(jù)的傳遞要销,并不會(huì)影響函數(shù)的執(zhí)行,所以 resolve 和 reject 后面如果有可以正常執(zhí)行的流程代碼夏块,它們?nèi)匀粫?huì)被正常執(zhí)行疏咐。如果不想這樣纤掸,可以使用 return 強(qiáng)制函數(shù)執(zhí)行的結(jié)束。

2. Promise 實(shí)例方法

(1) Promise.prototype.then()

Promise 實(shí)例生成以后浑塞,可以用 then 方法來(lái)指定 Resolved 狀態(tài)和 Rejected 狀態(tài)的回調(diào)函數(shù)

promise.then((payload) => {
  // Resolved 時(shí)執(zhí)行
}, (error) => {
  // Rejected 時(shí)執(zhí)行
});

Promise.prototype.then() 的兩個(gè)參數(shù)都需要傳遞函數(shù)借跪,代表著兩個(gè)狀態(tài)轉(zhuǎn)變所要執(zhí)行的回調(diào),每個(gè)回調(diào)都可以接受 Promise 對(duì)象狀態(tài)轉(zhuǎn)變時(shí)傳出的值作為參數(shù)酌壕。其中掏愁,then() 的第二個(gè)函數(shù)是可選的。

回到一開(kāi)始我們舉的 “栗子”卵牍,現(xiàn)在果港,我想通過(guò) Promise 的方式來(lái)實(shí)現(xiàn)多個(gè)異步程序的依次執(zhí)行,我們可以在 then() 的調(diào)用中顯式的返回一個(gè)新的 Promise 實(shí)例糊昙,然后就可以鏈?zhǔn)降那乙来蔚膱?zhí)行 then()辛掠,看下面的代碼:

const promise = new Promise((resolve, reject) => {
  // 模擬異步程序 1:睡覺(jué) 1s
  setTimeout(() => {
    resolve('睡完覺(jué)了');
  }, 1000);
});

promise.then((val) => {
  console.log(val);
  return (new Promise((resolve, reject) => {
    // 模擬異步程序 2:吃飯 1s
    setTimeout(() => {
      resolve('吃完飯了');
    }, 1000);
  }));
}).then((val) => {
  console.log(val);
  return (new Promise((resolve, reject) => {
    // 模擬異步程序 3:喝水 1s
    setTimeout(() => {
      resolve('喝完水了');
    }, 1000);
  }));
}).then((val) => {
  console.log(val);
});

通過(guò)在 then() 的第一個(gè)回調(diào)函數(shù)中,返回新的 Promise 實(shí)例释牺,我們可以用同步的流程將異步的操作表示出萝衩,相比使用 callback 更加的邏輯清晰。

(2) Promise.prototype.catch()

Promise.prototype.catch 方法是 .then(null, rejection) 的別名没咙,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)猩谊,也可以捕獲 then() 運(yùn)行中所拋出的錯(cuò)誤。

一般來(lái)說(shuō)镜撩,好的方式是不再 then() 里面指定 Rejected 的回調(diào)预柒,而是使用 catch() 來(lái)對(duì)所有錯(cuò)誤的捕獲(包括 then() 里面拋出的錯(cuò)誤)

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  }, 1000);
});

promise.then(() => {
  return temp + 2;
}).catch((error) => {
  console.error(error);
});

// ReferenceError: temp is not defined

3. Promise 類(lèi)級(jí)別方法

(1)Promise.all()

Promise.all() 方法用于將多個(gè) Promise 實(shí)例包裝成一個(gè)新的 Promise 實(shí)例。

Promise.all() 接受一個(gè)類(lèi)數(shù)組(具有 Iterator)作為參數(shù)袁梗,每個(gè)成員應(yīng)為 Promise 實(shí)例宜鸯,如果不是,會(huì)調(diào)用 Promise.resolve() 方法將其轉(zhuǎn)換為 Promise 實(shí)例遮怜。

Promise.all() 返回的新的 Promise 實(shí)例的狀態(tài)由傳遞的類(lèi)數(shù)組成員的共同狀態(tài)決定:

  • 當(dāng)所有成員的狀態(tài)都變?yōu)?Resolved淋袖,Promise 實(shí)例的狀態(tài)才會(huì)變?yōu)?Resolved,此時(shí)所有成員的返回值組成一個(gè)數(shù)組锯梁,傳遞給 Promise 實(shí)例的回調(diào)函數(shù)
  • 只要有一個(gè)成員的狀態(tài)變?yōu)?Rejected即碗,Promise 實(shí)例的狀態(tài)就變成 Rejected,此時(shí)第一個(gè)被 Rejected 的實(shí)例的返回值會(huì)傳遞給 Promise 實(shí)例的回調(diào)函數(shù)

如果作為 Promise.all() 參數(shù)的 Promise 實(shí)例自己定義了 catch 方法陌凳,那么它的狀態(tài)變?yōu)?Rejected 時(shí)剥懒,只會(huì)觸發(fā)它自己的 catch(),不會(huì)觸發(fā) Promise.all() 的 catch()

(2)Promise.race()

Promise.race() 方法和 Promise.all() 幾乎是一樣的合敦,只是對(duì)狀態(tài)的處理存在差別初橘。

Promise.race() 返回的新的 Promise 實(shí)例的狀態(tài)由傳遞的類(lèi)數(shù)組成員中最先改變狀態(tài)的成員的狀態(tài)決定。

(3)Promise.resolve()

Promise.resolve() 將現(xiàn)有對(duì)象轉(zhuǎn)換為 Promise 對(duì)象。

Promise.resolve() 的參數(shù)分成四種情況:

  • Promise 實(shí)例:直接返回這個(gè)實(shí)例保檐。
  • thenable 對(duì)象
    • thenable 對(duì)象指的是具有 then 方法的對(duì)象耕蝉。
    • Promise.resolve() 會(huì)將這個(gè)對(duì)象轉(zhuǎn)為 Promise 對(duì)象,然后就立即執(zhí)行 thenable 對(duì)象的 then 方法夜只,相當(dāng)于將這個(gè)對(duì)象的 then 方法作為 Promise 構(gòu)造函數(shù)的參數(shù)垒在,返回一個(gè)新的 Promise 實(shí)例。
  • 其余情況
    • Promise.resolve() 返回一個(gè)新的 Promise 對(duì)象扔亥,狀態(tài)為 Resolved场躯,使用 then() 時(shí),會(huì)將 Promise.resolve() 的參數(shù)傳遞給 then() 的回調(diào)函數(shù)中砸王。
    • 這個(gè)立即 Resolved 的 Promise 對(duì)象推盛,實(shí)在本次 “事件循環(huán)” 的結(jié)束時(shí)才開(kāi)始執(zhí)行峦阁。

(4)Promise.reject()

Promise.reject() 會(huì)返回一個(gè)新的 Promise 實(shí)例谦铃,狀態(tài)為 Rejected。

Promise.reject() 等價(jià)于下面的寫(xiě)法:

Promise.reject(obj);
// 等價(jià)于
new Promise((resolve, reject) => reject(obj));

Promise.reject() 會(huì)將參數(shù)原封不動(dòng)的作為 reject() 的參數(shù)榔昔。

三. Promise 深度剖析

1. Promise 與 setTimeout

我們來(lái)看這樣的一段代碼:

setTimeout(() => {
  console.log(1);
}, 0);

(new Promise((resolve, reject) => {
  resolve();
})).then(() => {
  console.log(2);
});

console.log(3);

這段代碼的運(yùn)行結(jié)果的順序是 3驹闰,2,1撒会,原因如下:

  • 對(duì)于 setTimeout 我們應(yīng)該都知道嘹朗,它是放在下一輪 “事件循環(huán)” 的開(kāi)始,所以它一定要在本輪事件結(jié)束后才會(huì)執(zhí)行诵肛,也就是輸出 1 一定要在輸出 3 以后
  • 接下來(lái)就是 Promise 異步執(zhí)行的問(wèn)題屹培,雖然 Promise 實(shí)例中并沒(méi)有真正意義上的異步程序,而是直接將狀態(tài)變更為 Resolved怔檩,且立即使用 then 進(jìn)行狀態(tài)的觀察褪秀,但是實(shí)質(zhì)上,立即 Resolved 的 Promise 是在本輪事件循環(huán)的末尾執(zhí)行薛训,總是晚于本輪循環(huán)的同步任務(wù)媒吗,所以,輸出 2 一定要在輸出 3 以后
  • 最后乙埃,就是 Promise 和 setTimeout 之間的問(wèn)題闸英,上面也說(shuō)到了,setTimeout 是在下一輪事件的開(kāi)始介袜,而 Promise 又實(shí)在本一輪事件的結(jié)束甫何,所以,很明顯遇伞,輸出 1 要在輸出 2 以后

2. 多層級(jí) .then()

一個(gè) Promise 實(shí)例可以連續(xù)使用 .then() 來(lái)綁定回調(diào)函數(shù):

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  }, 1000);
});

promise.then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
});

// 1
// 2

如果在 .then() 的回調(diào)中顯式的指定一個(gè)返回值(非 Promise 實(shí)例)辙喂,這個(gè)值會(huì)被作為下一個(gè)鏈?zhǔn)?.then() 回調(diào)函數(shù)中的參數(shù):

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  }, 1000);
});

promise.then(() => {
  console.log(1);
  return 'Promise';
}).then((val) => {
  console.log(val);
});

// 1
// Promise

如果在 .then() 的回調(diào)中返回的是一個(gè) Promise 實(shí)例,那么下一個(gè)鏈?zhǔn)?.then() 會(huì)在這個(gè) Promise 實(shí)例的狀態(tài)變更時(shí)會(huì)被調(diào)用,并且 resolve 所傳遞的值會(huì)被作為下一個(gè)鏈?zhǔn)?.then() 回調(diào)函數(shù)中的參數(shù):

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  }, 1000);
});

promise.then(() => {
  console.log(1);
  return (new Promise((resolve, reject) => {
    setTimeout(function() {
      resolve('Promise');
    }, 1000);
  }));
}).then((val) => {
  console.log(val);
});

// 1
// Promise
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末加派,一起剝皮案震驚了整個(gè)濱河市叫确,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芍锦,老刑警劉巖竹勉,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異娄琉,居然都是意外死亡次乓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)孽水,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)票腰,“玉大人,你說(shuō)我怎么就攤上這事女气⌒游浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵炼鞠,是天一觀的道長(zhǎng)缘滥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谒主,這世上最難降的妖魔是什么朝扼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮霎肯,結(jié)果婚禮上擎颖,老公的妹妹穿的比我還像新娘。我一直安慰自己观游,他們只是感情好搂捧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著备典,像睡著了一般异旧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上提佣,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天吮蛹,我揣著相機(jī)與錄音,去河邊找鬼拌屏。 笑死潮针,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倚喂。 我是一名探鬼主播每篷,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓣戚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了焦读?” 一聲冷哼從身側(cè)響起子库,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎矗晃,沒(méi)想到半個(gè)月后仑嗅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡张症,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年仓技,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俗他。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脖捻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兆衅,到底是詐尸還是另有隱情地沮,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布涯保,位于F島的核電站诉濒,受9級(jí)特大地震影響周伦,放射性物質(zhì)發(fā)生泄漏夕春。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一专挪、第九天 我趴在偏房一處隱蔽的房頂上張望及志。 院中可真熱鬧,春花似錦寨腔、人聲如沸速侈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)倚搬。三九已至,卻和暖如春乾蛤,著一層夾襖步出監(jiān)牢的瞬間每界,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工家卖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留眨层,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓上荡,卻偏偏與公主長(zhǎng)得像趴樱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • 00、前言Promise 是異步編程的一種解決方案捺疼,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大塞祈。它由社區(qū)...
    夜幕小草閱讀 2,133評(píng)論 0 12
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果帅涂,語(yǔ)法上說(shuō)议薪,Pr...
    雨飛飛雨閱讀 3,358評(píng)論 0 19
  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,170評(píng)論 0 16
  • nhhiuftyiy
    zf1閱讀 231評(píng)論 0 0
  • 95年的大水瓶 喜歡吃零食愛(ài)唱歌 雖然唱的不怎么樣。愛(ài)跑步喜歡自拍有點(diǎn)臭美哈醇锚。愛(ài)逛街喜歡旅游哼御。所以互相認(rèn)識(shí)一下咯 ...
    偶然的邂逅閱讀 108評(píng)論 0 0