Promise筆記

Promise學(xué)習(xí)(上):

資料: JavaScript Promise迷你書?

原著:azu / 翻譯:liubin窒所、kaku喳瓣、honnkyou?Version 1.4.1? ?/??http://liubin.org/promises-book/

概括筆記:

一衬衬、promise基本概念

1点骑、Promise是抽象異步處理對(duì)象以及對(duì)其進(jìn)行各種操作的組件刨肃。

2圃阳、Promise并不是從JavaScript中發(fā)祥的概念孽文。Promise最初被提出是在E語(yǔ)言中驻襟, 它是基于并列/并行處理設(shè)計(jì)的一種編程語(yǔ)言。

3叛溢、Promise把類似的異步處理對(duì)象和處理規(guī)則進(jìn)行規(guī)范化塑悼, 并按照采用統(tǒng)一的接口來(lái)編寫,而采取規(guī)定方法之外的寫法都會(huì)出錯(cuò)楷掉。

4厢蒜、創(chuàng)建一個(gè)promise對(duì)象

從構(gòu)造函數(shù)?Promise?來(lái)創(chuàng)建一個(gè)新建新promise對(duì)象作為接口。使用new來(lái)調(diào)用Promise的構(gòu)造器來(lái)進(jìn)行實(shí)例化promise對(duì)象烹植。

var?promise =?new?Promise(function(resolve, reject) { ?

??// 異步處理?

?// 處理結(jié)束后斑鸦、調(diào)用resolve 或 reject

});

5、promise.then()?實(shí)例回調(diào)方法

promise.then()?實(shí)例promise對(duì)象在?resolve(成功) /?reject(失敗)時(shí)調(diào)用的回調(diào)函數(shù)草雕。promise.then(onFulfilled, onRejected)巷屿。

resolve(成功)時(shí)onFulfilled?會(huì)被調(diào);reject(失敗)時(shí)onRejected?會(huì)被調(diào)用墩虹;onFulfilled嘱巾、onRejected?兩個(gè)都為可選參數(shù)。

promise.then?成功和失敗時(shí)都可以使用诫钓。 如果只想對(duì)異常進(jìn)行處理則可以采用?promise.then(undefined, onRejected)?方式菩浙,只指定reject時(shí)的回調(diào)函數(shù)勉痴。 不過promise除了then吨娜,還有catch方法巷折,捕獲失敗的處理。 promise.catch(onRejected)?惧所。promise.catch(onRejected)骤坐。

6、簡(jiǎn)單的例子

function?asyncFunction() {

? ?return?new?Promise(function?(resolve, reject) {

? ? ?setTimeout(function?() {

? ? ? ? resolve(value); ? ??

},?16); ? ?

});?

}

asyncFunction().then(function?(value) {

?console.log(value); ?

??// => value

}).catch(function?(error) {

??console.log(error);?

});

asyncFunction?函數(shù)返回promise對(duì)象下愈,?then?方法設(shè)置resolve后的回調(diào)函數(shù)纽绍,?catch方法設(shè)置發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。在這種情況下 驰唬,catch?的回調(diào)函數(shù)不會(huì)被執(zhí)行(因?yàn)閜romise返回了resolve)顶岸, 如果運(yùn)行環(huán)境沒有提供?setTimeout?函數(shù)腔彰,那么上面代碼在執(zhí)行中就會(huì)產(chǎn)生異常叫编,在執(zhí)行catch?中設(shè)置的回調(diào)函數(shù)辖佣。

?* 不使用catch?方法:

我們可以使用promise.then(onFulfilled, onRejected)?方法聲明,只使用?then方法搓逾。

asyncFunction().then(function?(value) {

?? ?console.log(value);?

},function?(error) {

??console.log(error);?

});

7卷谈、實(shí)例化的promise對(duì)象的狀態(tài)。

"has-resolution" - Fulfilled :

resolve(成功)時(shí)霞篡。此時(shí)會(huì)調(diào)用?onFulfilled世蔗。

"has-rejection" - Rejected :

reject(失敗)時(shí)。此時(shí)會(huì)調(diào)用?onRejected朗兵。

"unresolved" - Pending :

既不是resolve也不是reject的狀態(tài)污淋。也就是promise對(duì)象剛被創(chuàng)建后的初始化狀態(tài)等。

其中 左側(cè)為在ES6 Promises規(guī)范中定義的術(shù)語(yǔ)余掖, 而右側(cè)則是在Promises/A+中描述狀態(tài)的術(shù)語(yǔ)寸爆。

8、promise對(duì)象的狀態(tài)盐欺,從Pending轉(zhuǎn)換為FulfilledRejected之后赁豆, 這個(gè)promise對(duì)象的狀態(tài)就不會(huì)再發(fā)生任何變化。在.then?后執(zhí)行的函數(shù)只會(huì)被調(diào)用一次冗美。FulfilledRejected這兩個(gè)中的任一狀態(tài)都可以表示為Settled(不變的)魔种。Settled 代表?resolve(成功) 或 reject(失敗)。

* 關(guān)鍵點(diǎn):當(dāng)promise的對(duì)象狀態(tài)發(fā)生變化時(shí)粉洼,用.then?來(lái)定義只會(huì)被調(diào)用一次的函數(shù)节预。

二、創(chuàng)建promise對(duì)象

1属韧、創(chuàng)建promise對(duì)象的流程安拟。

1.1、實(shí)例化promise對(duì)象:new Promise(fn)?返回一個(gè)promise對(duì)象

1.2挫剑、在fn?中指定異步等處理

處理結(jié)果錯(cuò)誤的話去扣,調(diào)用reject(Error對(duì)象)

處理結(jié)果正常的話,調(diào)用resolve(處理結(jié)果值)

2樊破、為promise對(duì)象添加處理方法

promise對(duì)象的處理方法有兩種:

promise對(duì)象被?resolve?時(shí)的處理(onFulfilled)

promise對(duì)象被?reject?時(shí)的處理(onRejected)

被resolve后的處理愉棱,可以在.then?方法中傳入想要調(diào)用的函數(shù)。(如下面例子)getURL函數(shù)中的?resolve(req.responseText);?會(huì)將promise對(duì)象變?yōu)閞esolve(Fulfilled)狀態(tài)哲戚, 同時(shí)使用其值調(diào)用?onFulfilled?函數(shù)奔滑。

在getURL?的處理中發(fā)生任何異常,或者被明確reject的情況下顺少, 該異常原因(Error對(duì)象)會(huì)作為.catch方法的參數(shù)被調(diào)用朋其。

例子:? 用Promise來(lái)通過異步處理方式來(lái)獲取XMLHttpRequest(XHR)的數(shù)據(jù) :

聲明一個(gè)getURL函數(shù)王浴,返回一個(gè)promise實(shí)例包裝XHR處理。

function?getURL(URL) { ?

??return?new?Promise(function?(resolve, reject) {

? ?var?req =?new?XMLHttpRequest();

? ?req.open('GET', URL,?true);

?req.onload?=?function?() {

?? ? ? ?if?(req.status ===?200) { ? ? ? ??

? ? ? ?resolve(req.responseText); ? ? ? ? ?

}?else?{

? ?reject(new?Error(req.statusText));

?? ?} ? ?

?? ?}; ? ??

? ?req.onerror?=?function?() {

?? ?reject(new?Error(req.statusText));

? ?}; ? ??

? ?req.send(); ?

??});?

}

// 運(yùn)行示例

var?URL =?"http://httpbin.org/get";

getURL(URL).then(function?onFulfilled(value){?//?被resolve后的處理梅猿,可以在.then方法中傳入想要調(diào)用的函數(shù)氓辣。

??console.log(value);

?}).catch(function?onRejected(error){?//?被reject后的處理,可以在.then 的第二個(gè)參數(shù)或者是在.catch方法中設(shè)置想要調(diào)用的函數(shù)袱蚓。

??console.error(error);

?});

getURL?只有在通過XHR取得結(jié)果狀態(tài)為200時(shí)才會(huì)調(diào)用?resolve?-其他情況(取得失敵ァ)則調(diào)用?reject?方法。

XHR發(fā)生錯(cuò)誤時(shí)?onerror?事件被觸發(fā)喇潘,調(diào)用reject体斩。發(fā)生錯(cuò)誤時(shí)需要?jiǎng)?chuàng)建一個(gè)Error對(duì)象后再將具體的值傳進(jìn)去:reject(new Error(req.statusText));?。

3颖低、?Promise.resolve

new Promise()?方法的快捷方式:靜態(tài)方法Promise.resolve(value)絮吵。

例如:

基本的用法:

new?Promise(function(resolve){ ?

??resolve(42);? //resolve(42);?會(huì)讓promise對(duì)象立即進(jìn)入確定(resolved)狀態(tài),并將 value值42?傳遞給后面then里所指定的?onFulfilled?函數(shù)

});

語(yǔ)法糖:

Promise.resolve(42);

Promise.resolve(value)?方法的返回值是一個(gè)promise對(duì)象忱屑,可以對(duì)其返回值進(jìn)行?.then?調(diào)用蹬敲。

Promise.resolve(42).then(function(value){ ??

?console.log(value);

?});

?Promise.resolve?方法的作用就是將傳遞給它的參數(shù)填充(Fulfilled)到promise對(duì)象后并返回這個(gè)promise對(duì)象。

3.1想幻、Promise.resolve?方法另一個(gè)作用就是將thenable對(duì)象轉(zhuǎn)換為promise對(duì)象

(thenable指的是一個(gè)具有?.then?方法的對(duì)象粱栖。例如jQuery.ajax())。thenable對(duì)象可以使用?Promise.resolve?來(lái)轉(zhuǎn)換為一個(gè)promise對(duì)象脏毯。就能直接使用?then?或者?catch?等在ES6 Promises里定義的方法闹究。

3.1.1、將thenable對(duì)象轉(zhuǎn)換promise對(duì)象

var?promise = Promise.resolve($.ajax('/json/comment.json'));// => promise對(duì)象

promise.then(function(value){ ?

?console.log(value);

?});

*thenable?對(duì)象我們一般用不到

4食店、 Promise.reject

Promise.reject(error)是和Promise.resolve(value)類似的靜態(tài)方法渣淤,也是?new Promise()?方法的快捷方式。

常規(guī)寫法是:

new Promise(function(resolve,reject){ ??

?reject(new Error("error"));

?});? ? ? //調(diào)用該promise對(duì)象通過then指定的?onRejected?函數(shù)吉嫩,并將錯(cuò)誤(Error)對(duì)象傳遞給 onRejected?函數(shù)价认。

語(yǔ)法糖:

Promise.reject(new?Error("error")).catch(function(error){ ?

??console.error(error);?

});

5、promise異步操作

1自娩、一般的使用情況下用踩,接收回調(diào)函數(shù)的函數(shù),根據(jù)具體的執(zhí)行情況忙迁,可以選擇是以同步還是異步的方式對(duì)回調(diào)函數(shù)進(jìn)行調(diào)用脐彩。

異步回調(diào)函數(shù)同步調(diào)用 ?

NO!!!

1、絕對(duì)不能對(duì)異步回調(diào)函數(shù)(即使在數(shù)據(jù)已經(jīng)就緒)進(jìn)行同步調(diào)用姊扔。

2惠奸、如果對(duì)異步回調(diào)函數(shù)進(jìn)行同步調(diào)用的話,處理順序可能會(huì)與預(yù)期不符恰梢,可能帶來(lái)意料之外的后果佛南。

3梗掰、對(duì)異步回調(diào)函數(shù)進(jìn)行同步調(diào)用,還可能導(dǎo)致棧溢出或異常處理錯(cuò)亂等問題嗅回。

4及穗、如果想在將來(lái)某時(shí)刻調(diào)用異步回調(diào)函數(shù)的話,可以使用?setTimeout?等異步API妈拌。

例子:

這個(gè)函數(shù)會(huì)接收一個(gè)回調(diào)函數(shù)進(jìn)行處理拥坛。

function?onReady(fn) { ??

?var?readyState = document.readyState;

??if?(readyState ===?'interactive'?|| readyState ===?'complete') { ? ?

?? ?fn(); ?

}?else?{

? ? ?window.addEventListener('DOMContentLoaded', fn);?

?? ?}

?}

?onReady(function?() {

?? ?console.log('DOM fully loaded and parsed');

?});?

console.log('==Starting==');

如果在調(diào)用onReady之前DOM已經(jīng)載入的話

如果在調(diào)用onReady之前DOM還沒有載入的話

對(duì)回調(diào)函數(shù)進(jìn)行同步調(diào)用

通過注冊(cè)?DOMContentLoaded?事件監(jiān)聽器來(lái)對(duì)回調(diào)函數(shù)進(jìn)行異步調(diào)用

因此蓬蝶,如果這段代碼在源文件中出現(xiàn)的位置不同尘分,在控制臺(tái)上打印的log消息順序也會(huì)不同。為了解決這個(gè)問題丸氛,我們可以選擇統(tǒng)一使用異步調(diào)用的方式培愁。

例子2:

setTimeout?等異步API異步調(diào)用回調(diào)函數(shù):

function?onReady(fn) { ?

??var?readyState = document.readyState;

??if?(readyState ===?'interactive'?|| readyState ===?'complete') { ? ? ?

setTimeout(fn,?0); ??

}?else?{

??window.addEventListener('DOMContentLoaded', fn); ?

??}?

}?

onReady(function?() {

?? ?console.log('DOM fully loaded and parsed');

?});

?console.log('==Starting==');

為了避免上述中同時(shí)使用同步、異步調(diào)用可能引起的混亂問題缓窜,Promise在規(guī)范上規(guī)定?Promise只能使用異步調(diào)用方式?定续。

例子三:

promise重寫上述onReady函數(shù):

function?onReadyPromise() { ?

??return?new?Promise(function?(resolve, reject) {

??var?readyState = document.readyState;

?? ?if?(readyState ===?'interactive'?|| readyState ===?'complete') { ? ? ? ? ?

??resolve(); ??

}?else?{

? ? ? ?window.addEventListener('DOMContentLoaded', resolve); ? ?

?? ?} ?

??});?

}?

onReadyPromise().then(function?() {

?console.log('DOM fully loaded and parsed');

?});?

console.log('==Starting==');

Promise能保證每次調(diào)用都是以異步方式進(jìn)行。

6禾锤、Promise 方法鏈method chain

function?taskA() { ?

??console.log("Task A");?

}

function?taskB() { ??

?console.log("Task B");?

}

function?onRejected(error) { ?

??console.log("Catch Error: A or B", error);?

}

function?finalTask() { ??

?console.log("Final Task");?

}

var?promise = Promise.resolve();

?promise

.then(taskA)

.then(taskB)

.catch(onRejected)?

.then(finalTask);

執(zhí)行流程:

6.1私股、promise chain 中如何傳遞參數(shù)

function?doubleUp(value) { ?

??return?value *?2;

?}

function?increment(value) { ?

??return?value +?1;

?}

function?output(value) { ?

??console.log(value);// => (1 + 1) * 2

}

var?promise = Promise.resolve(1);?

promise

.then(increment)

.then(doubleUp)

.then(output)

.catch(function(error){?

??// promise chain中出現(xiàn)異常的時(shí)候會(huì)被調(diào)用?

console.error(error); ??

?});

入口函數(shù)是?Promise.resolve(1);?

執(zhí)行流程:Promise.resolve(1);?傳遞 1 給?increment?函數(shù);函數(shù)?increment?對(duì)接收的參數(shù)進(jìn)行 +1 操作并返回結(jié)果恩掷,接著傳給?doubleUp?函數(shù)倡鲸;最后在函數(shù)?output?中打印結(jié)果。

* return的值會(huì)由?Promise.resolve(return的返回值);?進(jìn)行相應(yīng)的包裝處理黄娘,最終?then?的結(jié)果返回一個(gè)新創(chuàng)建的promise對(duì)象峭状。Promise#then?除了注冊(cè)一個(gè)回調(diào)函數(shù),還將回調(diào)函數(shù)的返回值進(jìn)行變換逼争,創(chuàng)建并返回一個(gè)promise對(duì)象优床。

特別注意的地方:then?返回返回新創(chuàng)建的promise對(duì)象。

例子:??then?的錯(cuò)誤使用方法

function?badAsyncCall() { ?

??var?promise = Promise.resolve();

??promise.then(function() { ? ?

?? ?// 任意處理?

?return?newVar;

?}); ??

?return?promise;

?}

正確方法:then?返回返回新創(chuàng)建的promise對(duì)象

function?anAsyncCall() { ?

??var?promise = Promise.resolve();

??return?promise.then(function() { ??

? ? ?// 任意處理?

? ?return?newVar;

?});

?}

這種函數(shù)的行為貫穿在Promise整體之中誓焦,接收一個(gè)promise對(duì)象為參數(shù)胆敞,并返回一個(gè)和接收參數(shù)不同的、新的promise對(duì)象杂伟。


7移层、 使用Promise#then同時(shí)處理多個(gè)異步請(qǐng)求

7.1、Promise.all

Promise.all?接收一個(gè) promise對(duì)象的數(shù)組作為參數(shù)稿壁,當(dāng)這個(gè)數(shù)組里的所有promise對(duì)象全部變?yōu)閞esolve或reject狀態(tài)的時(shí)候幽钢,它才會(huì)去調(diào)用?.then?方法。

例子:

function?getURL(URL) { ??

?return?new?Promise(function?(resolve, reject) {

?? ? ?var?req =?new?XMLHttpRequest();

? ?req.open('GET', URL,?true); ??

? ? ?req.onload?=?function?() {

?? ? ? ?if?(req.status ===?200) { ? ?

?? ? ? ? ? ?resolve(req.responseText); ??

}?else?{

?? ? ? ? ? ?reject(new?Error(req.statusText));

?? ? ? ? ?} ? ? ?

??}; ? ? ??

?req.onerror?=?function?() {

? ? ?reject(new?Error(req.statusText));

?? ? ?}; ?

?? ? ?req.send(); ?

??});?

}

var?request = {

? ?comment:?function?getComment() { ? ? ??

? ? ?return?getURL('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse); ? ??

? ?}, ? ? ?

??people:?function?getPeople() { ? ??

? ? ? ?return?getURL('http://azu.github.io/promises-book/json/people.json').then(JSON.parse); ? ?

?? ?} ? ?

};

function?main() { ?

??return?Promise.all([request.comment(), request.people()]);

}

// 運(yùn)行示例

main().then(function?(value) {

?? ?console.log(value);

?}).catch(function(error){ ?

??console.log(error);?

});

// request.comment()?和?request.people()?會(huì)同時(shí)開始執(zhí)行傅是,而且每個(gè)promise的結(jié)果(resolve或reject時(shí)傳遞的參數(shù)值)匪燕,和傳遞給Promise.all的promise數(shù)組的順序一致蕾羊。

7.2、Promise.all?在接收到的所有的對(duì)象promise都變?yōu)?FulFilled 或者 Rejected 狀態(tài)之后才會(huì)繼續(xù)進(jìn)行后面的處理帽驯。

?與之相對(duì)的是?Promise.race?龟再。只要有一個(gè)promise對(duì)象進(jìn)入 FulFilled 或者 Rejected 狀態(tài)的話,就會(huì)繼續(xù)進(jìn)行后面的處理尼变。

暫時(shí)學(xué)習(xí)到前兩章利凑,東西太多,一時(shí)間消化不了嫌术。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哀澈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子度气,更是在濱河造成了極大的恐慌割按,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件磷籍,死亡現(xiàn)場(chǎng)離奇詭異适荣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)院领,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門弛矛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人比然,你說(shuō)我怎么就攤上這事丈氓。” “怎么了谈秫?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扒寄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拟烫,道長(zhǎng)该编,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任硕淑,我火速辦了婚禮课竣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘置媳。我一直安慰自己于樟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布拇囊。 她就那樣靜靜地躺著迂曲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寥袭。 梳的紋絲不亂的頭發(fā)上路捧,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天关霸,我揣著相機(jī)與錄音,去河邊找鬼杰扫。 笑死队寇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的章姓。 我是一名探鬼主播佳遣,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凡伊!你這毒婦竟也來(lái)了零渐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窗声,失蹤者是張志新(化名)和其女友劉穎相恃,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笨觅,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年耕腾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了见剩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扫俺,死狀恐怖苍苞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狼纬,我是刑警寧澤羹呵,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站疗琉,受9級(jí)特大地震影響冈欢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盈简,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一凑耻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柠贤,春花似錦香浩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宴霸,卻和暖如春囱晴,著一層夾襖步出監(jiān)牢的瞬間岸裙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工速缆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留降允,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓艺糜,卻偏偏與公主長(zhǎng)得像剧董,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子破停,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353