<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你寫出符合Promise/A+規(guī)范Promise的源碼

          共 13441字,需瀏覽 27分鐘

           ·

          2020-07-24 22:20

          Promise是前端面試中的高頻問題,如果你能根據(jù)PromiseA+的規(guī)范,寫出符合規(guī)范的源碼,那么我想,對(duì)于面試中的Promise相關(guān)的問題,都能夠給出比較完美的答案。

          我的建議是,對(duì)照規(guī)范多寫幾次實(shí)現(xiàn),也許第一遍的時(shí)候,是改了多次,才能通過測試,那么需要反復(fù)的寫,我已經(jīng)將Promise的源碼實(shí)現(xiàn)寫了不下七遍,不那么聰明的話,當(dāng)然需要更加努力啦~

          56ef9e7b8537576e2b62bd1a3db13d1d.webp

          Promise的源碼實(shí)現(xiàn)

          /**
          ?*?1.?new?Promise時(shí),需要傳遞一個(gè)?executor?執(zhí)行器,執(zhí)行器立刻執(zhí)行
          ?*?2.?executor?接受兩個(gè)參數(shù),分別是?resolve?和?reject
          ?*?3.?promise?只能從?pending?到?rejected,?或者從?pending?到?fulfilled
          ?*?4.?promise?的狀態(tài)一旦確認(rèn),就不會(huì)再改變
          ?*?5.?promise?都有?then?方法,then?接收兩個(gè)參數(shù),分別是?promise?成功的回調(diào)?onFulfilled,?
          ?*??????和?promise?失敗的回調(diào)?onRejected
          ?* 6. 如果調(diào)用 then 時(shí),promise已經(jīng)成功,則執(zhí)行 onFulfilled,并將promise的值作為參數(shù)傳遞進(jìn)去。
          ?*??????如果promise已經(jīng)失敗,那么執(zhí)行 onRejected, 并將 promise 失敗的原因作為參數(shù)傳遞進(jìn)去。
          ?*??????如果promise的狀態(tài)是pending,需要將onFulfilled和onRejected函數(shù)存放起來,等待狀態(tài)確定后,再依次將對(duì)應(yīng)的函數(shù)執(zhí)行(發(fā)布訂閱)
          ?*?7.?then?的參數(shù)?onFulfilled?和?onRejected?可以缺省
          ?*?8.?promise?可以then多次,promise?的then?方法返回一個(gè)?promise
          ?*?9.?如果?then?返回的是一個(gè)結(jié)果,那么就會(huì)把這個(gè)結(jié)果作為參數(shù),傳遞給下一個(gè)then的成功的回調(diào)(onFulfilled)
          ?*?10.?如果?then?中拋出了異常,那么就會(huì)把這個(gè)異常作為參數(shù),傳遞給下一個(gè)then的失敗的回調(diào)(onRejected)
          ?*?11.如果?then?返回的是一個(gè)promise,那么會(huì)等這個(gè)promise執(zhí)行完,promise如果成功,
          ?*???就走下一個(gè)then的成功,如果失敗,就走下一個(gè)then的失敗
          ?*/


          const?PENDING?=?'pending';
          const?FULFILLED?=?'fulfilled';
          const?REJECTED?=?'rejected';
          function?Promise(executor)?{
          ????let?self?=?this;
          ????self.status?=?PENDING;
          ????self.onFulfilled?=?[];//成功的回調(diào)
          ????self.onRejected?=?[];?//失敗的回調(diào)
          ????//PromiseA+?2.1
          ????function?resolve(value)?{
          ????????if?(self.status?===?PENDING)?{
          ????????????self.status?=?FULFILLED;
          ????????????self.value?=?value;
          ????????????self.onFulfilled.forEach(fn?=>?fn());//PromiseA+?2.2.6.1
          ????????}
          ????}

          ????function?reject(reason)?{
          ????????if?(self.status?===?PENDING)?{
          ????????????self.status?=?REJECTED;
          ????????????self.reason?=?reason;
          ????????????self.onRejected.forEach(fn?=>?fn());//PromiseA+?2.2.6.2
          ????????}
          ????}

          ????try?{
          ????????executor(resolve,?reject);
          ????}?catch?(e)?{
          ????????reject(e);
          ????}
          }

          Promise.prototype.then?=?function?(onFulfilled,?onRejected)?{
          ????//PromiseA+?2.2.1?/?PromiseA+?2.2.5?/?PromiseA+?2.2.7.3?/?PromiseA+?2.2.7.4
          ????onFulfilled?=?typeof?onFulfilled?===?'function'???onFulfilled?:?value?=>?value;
          ????onRejected?=?typeof?onRejected?===?'function'???onRejected?:?reason?=>?{?throw?reason?};
          ????let?self?=?this;
          ????//PromiseA+?2.2.7
          ????let?promise2?=?new?Promise((resolve,?reject)?=>?{
          ????????if?(self.status?===?FULFILLED)?{
          ????????????//PromiseA+?2.2.2
          ????????????//PromiseA+?2.2.4?---?setTimeout
          ????????????setTimeout(()?=>?{
          ????????????????try?{
          ????????????????????//PromiseA+?2.2.7.1
          ????????????????????let?x?=?onFulfilled(self.value);
          ????????????????????resolvePromise(promise2,?x,?resolve,?reject);
          ????????????????}?catch?(e)?{
          ????????????????????//PromiseA+?2.2.7.2
          ????????????????????reject(e);
          ????????????????}
          ????????????});
          ????????}?else?if?(self.status?===?REJECTED)?{
          ????????????//PromiseA+?2.2.3
          ????????????setTimeout(()?=>?{
          ????????????????try?{
          ????????????????????let?x?=?onRejected(self.reason);
          ????????????????????resolvePromise(promise2,?x,?resolve,?reject);
          ????????????????}?catch?(e)?{
          ????????????????????reject(e);
          ????????????????}
          ????????????});
          ????????}?else?if?(self.status?===?PENDING)?{
          ????????????self.onFulfilled.push(()?=>?{
          ????????????????setTimeout(()?=>?{
          ????????????????????try?{
          ????????????????????????let?x?=?onFulfilled(self.value);
          ????????????????????????resolvePromise(promise2,?x,?resolve,?reject);
          ????????????????????}?catch?(e)?{
          ????????????????????????reject(e);
          ????????????????????}
          ????????????????});
          ????????????});
          ????????????self.onRejected.push(()?=>?{
          ????????????????setTimeout(()?=>?{
          ????????????????????try?{
          ????????????????????????let?x?=?onRejected(self.reason);
          ????????????????????????resolvePromise(promise2,?x,?resolve,?reject);
          ????????????????????}?catch?(e)?{
          ????????????????????????reject(e);
          ????????????????????}
          ????????????????});
          ????????????});
          ????????}
          ????});
          ????return?promise2;
          }

          function?resolvePromise(promise2,?x,?resolve,?reject)?{
          ????let?self?=?this;
          ????//PromiseA+?2.3.1
          ????if?(promise2?===?x)?{
          ????????reject(new?TypeError('Chaining?cycle'));
          ????}
          ????if?(x?&&?typeof?x?===?'object'?||?typeof?x?===?'function')?{
          ????????let?used;?//PromiseA+2.3.3.3.3?只能調(diào)用一次
          ????????try?{
          ????????????let?then?=?x.then;
          ????????????if?(typeof?then?===?'function')?{
          ????????????????//PromiseA+2.3.3
          ????????????????then.call(x,?(y)?=>?{
          ????????????????????//PromiseA+2.3.3.1
          ????????????????????if?(used)?return;
          ????????????????????used?=?true;
          ????????????????????resolvePromise(promise2,?y,?resolve,?reject);
          ????????????????},?(r)?=>?{
          ????????????????????//PromiseA+2.3.3.2
          ????????????????????if?(used)?return;
          ????????????????????used?=?true;
          ????????????????????reject(r);
          ????????????????});

          ????????????}else{
          ????????????????//PromiseA+2.3.3.4
          ????????????????if?(used)?return;
          ????????????????used?=?true;
          ????????????????resolve(x);
          ????????????}
          ????????}?catch?(e)?{
          ????????????//PromiseA+?2.3.3.2
          ????????????if?(used)?return;
          ????????????used?=?true;
          ????????????reject(e);
          ????????}
          ????}?else?{
          ????????//PromiseA+?2.3.3.4
          ????????resolve(x);
          ????}
          }

          module.exports?=?Promise;

          有專門的測試腳本可以測試所編寫的代碼是否符合PromiseA+的規(guī)范。

          首先,在promise實(shí)現(xiàn)的代碼中,增加以下代碼:

          Promise.defer?=?Promise.deferred?=?function?()?{
          ????let?dfd?=?{};
          ????dfd.promise?=?new?Promise((resolve,?reject)?=>?{
          ????????dfd.resolve?=?resolve;
          ????????dfd.reject?=?reject;
          ????});
          ????return?dfd;
          }

          安裝測試腳本:

          npm?install?-g?promises-aplus-tests

          如果當(dāng)前的promise源碼的文件名為promise.js

          那么在對(duì)應(yīng)的目錄執(zhí)行以下命令:

          promises-aplus-tests?promise.js

          promises-aplus-tests中共有872條測試用例。以上代碼,可以完美通過所有用例。

          對(duì)上面的代碼實(shí)現(xiàn)做一點(diǎn)簡要說明(其它一些內(nèi)容注釋中已經(jīng)寫得很清楚):

          1. onFulfilled 和 onFulfilled的調(diào)用需要放在setTimeout,因?yàn)橐?guī)范中表示: onFulfilled or onRejected must not be called until the execution context stack contains only platform code。使用setTimeout只是模擬異步,原生Promise并非是這樣實(shí)現(xiàn)的。

          2. 在 resolvePromise 的函數(shù)中,為何需要usedd這個(gè)flag,同樣是因?yàn)橐?guī)范中明確表示: If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored. 因此我們需要這樣的flag來確保只會(huì)執(zhí)行一次。

          3. self.onFulfilled 和 self.onRejected 中存儲(chǔ)了成功的回調(diào)和失敗的回調(diào),根據(jù)規(guī)范2.6顯示,當(dāng)promise從pending態(tài)改變的時(shí)候,需要按照順序去指定then對(duì)應(yīng)的回調(diào)。

          PromiseA+的規(guī)范(翻譯版)

          PS: 下面是我翻譯的規(guī)范,供參考

          術(shù)語

          1. promise 是一個(gè)有then方法的對(duì)象或者是函數(shù),行為遵循本規(guī)范

          2. thenable 是一個(gè)有then方法的對(duì)象或者是函數(shù)

          3. value 是promise狀態(tài)成功時(shí)的值,包括 undefined/thenable或者是 promise

          4. exception 是一個(gè)使用throw拋出的異常值

          5. reason 是promise狀態(tài)失敗時(shí)的值

          要求

          2.1 Promise States

          Promise 必須處于以下三個(gè)狀態(tài)之一: pending, fulfilled 或者是 rejected

          2.1.1 如果promise在pending狀態(tài)
          2.1.1.1?可以變成?fulfilled?或者是?rejected
          2.1.2 如果promise在fulfilled狀態(tài)
          2.1.2.1?不會(huì)變成其它狀態(tài)

          2.1.2.2?必須有一個(gè)value
          2.1.3 如果promise在rejected狀態(tài)
          2.1.3.1?不會(huì)變成其它狀態(tài)

          2.1.3.2?必須有一個(gè)promiserejectreason

          概括即是:promise的狀態(tài)只能從pending變成fulfilled,或者從pending變成rejected.promise成功,有成功的value.promise失敗的話,有失敗的原因

          2.2 then方法

          promise必須提供一個(gè)then方法,來訪問最終的結(jié)果

          promise的then方法接收兩個(gè)參數(shù)

          promise.then(onFulfilled,?onRejected)
          2.2.1 onFulfilled 和 onRejected 都是可選參數(shù)
          2.2.1.1?onFulfilled?必須是函數(shù)類型

          2.2.1.2?onRejected?必須是函數(shù)類型
          2.2.2 如果 onFulfilled 是函數(shù):
          2.2.2.1?必須在promise變成?fulfilled?時(shí),調(diào)用?onFulfilled,參數(shù)是promisevalue
          2.2.2.2?在promise的狀態(tài)不是?fulfilled?之前,不能調(diào)用
          2.2.2.3?onFulfilled?只能被調(diào)用一次
          2.2.3 如果 onRejected 是函數(shù):
          2.2.3.1?必須在promise變成?rejected?時(shí),調(diào)用?onRejected,參數(shù)是promisereason
          2.2.3.2?在promise的狀態(tài)不是?rejected?之前,不能調(diào)用
          2.2.3.3?onRejected?只能被調(diào)用一次
          2.2.4 onFulfilled 和 onRejected 應(yīng)該是微任務(wù)
          2.2.5 onFulfilled ?和 onRejected 必須作為函數(shù)被調(diào)用
          2.2.6 then方法可能被多次調(diào)用
          2.2.6.1?如果promise變成了?fulfilled態(tài),所有的onFulfilled回調(diào)都需要按照then的順序執(zhí)行
          2.2.6.2?如果promise變成了?rejected態(tài),所有的onRejected回調(diào)都需要按照then的順序執(zhí)行
          2.2.7 then必須返回一個(gè)promise
          promise2?=?promise1.then(onFulfilled,?onRejected);
          2.2.7.1?onFulfilled?或?onRejected?執(zhí)行的結(jié)果為x,調(diào)用?resolvePromise
          2.2.7.2?如果?onFulfilled?或者?onRejected?執(zhí)行時(shí)拋出異常e,promise2需要被reject
          2.2.7.3?如果?onFulfilled?不是一個(gè)函數(shù),promise2?以promise1的值fulfilled
          2.2.7.4?如果?onRejected?不是一個(gè)函數(shù),promise2?以promise1reason?rejected

          2.3 resolvePromise

          resolvePromise(promise2, x, resolve, reject)

          2.3.1 如果 promise2 和 x 相等,那么 reject promise with a TypeError
          2.3.2 如果 x 是一個(gè) promsie
          2.3.2.1?如果xpending態(tài),那么promise必須要在pending,直到?x?變成?fulfilled?or?rejected.
          2.3.2.2?如果?x?被?fulfilled,?fulfill?promise?with?the?same?value.
          2.3.2.3?如果?x?被?rejected,?reject?promise?with?the?same?reason.
          2.3.3 如果 x 是一個(gè) object 或者 是一個(gè) function
          2.3.3.1?let?then?=?x.then.
          2.3.3.2?如果?x.then?這步出錯(cuò),那么?reject?promise?with?e?as?the?reason..
          2.3.3.3?如果?then?是一個(gè)函數(shù),then.call(x,?resolvePromiseFn,?rejectPromise)
          ????2.3.3.3.1?resolvePromiseFn 的?入?yún)⑹?y, 執(zhí)行 resolvePromise(promise2, y, resolve, reject);
          ????2.3.3.3.2?rejectPromise 的?入?yún)⑹?r, reject promise with?r.
          ????2.3.3.3.3?如果 resolvePromise 和 rejectPromise 都調(diào)用了,那么第一個(gè)調(diào)用優(yōu)先,后面的調(diào)用忽略。
          ????2.3.3.3.4?如果調(diào)用then拋出異常e?
          ????????2.3.3.3.4.1?如果?resolvePromise?或?rejectPromise?已經(jīng)被調(diào)用,那么忽略
          ????????2.3.3.3.4.3?否則,reject?promise?with?e?as?the?reason
          2.3.3.4?如果?then?不是一個(gè)function.?fulfill?promise?with?x.
          2.3.4 如果 x 不是一個(gè) object 或者 function,fulfill promise with x.

          Promise的其他方法

          雖然上述的promise源碼已經(jīng)符合PromiseA+的規(guī)范,但是原生的Promise還提供了一些其他方法,如:

          1. Promise.resolve()

          2. Promise.reject()

          3. Promise.prototype.catch()

          4. Promise.prototype.finally()

          5. Promise.all()

          6. Promise.race()

          下面具體說一下每個(gè)方法的實(shí)現(xiàn):

          Promise.resolve

          Promise.resolve(value) 返回一個(gè)以給定值解析后的Promise 對(duì)象.

          1. 如果 value 是個(gè) thenable 對(duì)象,返回的promise會(huì)“跟隨”這個(gè)thenable的對(duì)象,采用它的最終狀態(tài)

          2. 如果傳入的value本身就是promise對(duì)象,那么Promise.resolve將不做任何修改、原封不動(dòng)地返回這個(gè)promise對(duì)象。

          3. 其他情況,直接返回以該值為成功狀態(tài)的promise對(duì)象。

          Promise.resolve?=?function?(param)?{
          ????????if?(param?instanceof?Promise)?{
          ????????return?param;
          ????}
          ????return?new?Promise((resolve,?reject)?=>?{
          ????????if?(param?&&?typeof?param?===?'object'?&&?typeof?param.then?===?'function')?{
          ????????????setTimeout(()?=>?{
          ????????????????param.then(resolve,?reject);
          ????????????});
          ????????}?else?{
          ????????????resolve(param);
          ????????}
          ????});
          }

          thenable對(duì)象的執(zhí)行加 setTimeout的原因是根據(jù)原生Promise對(duì)象執(zhí)行的結(jié)果推斷的,如下的測試代碼,原生的執(zhí)行結(jié)果為: 20 ?400 ?30;為了同樣的執(zhí)行順序,增加了setTimeout延時(shí)。

          測試代碼:

          let?p?=?Promise.resolve(20);
          p.then((data)?=>?{
          ????console.log(data);
          });


          let?p2?=?Promise.resolve({
          ????then:?function(resolve,?reject)?{
          ????????resolve(30);
          ????}
          });

          p2.then((data)=>?{
          ????console.log(data)
          });

          let?p3?=?Promise.resolve(new?Promise((resolve,?reject)?=>?{
          ????resolve(400)
          }));
          p3.then((data)?=>?{
          ????console.log(data)
          });

          Promise.reject

          Promise.reject方法和Promise.resolve不同,Promise.reject()方法的參數(shù),會(huì)原封不動(dòng)地作為reject的理由,變成后續(xù)方法的參數(shù)。

          Promise.reject?=?function?(reason)?{
          ????return?new?Promise((resolve,?reject)?=>?{
          ????????reject(reason);
          ????});
          }

          Promise.prototype.catch

          Promise.prototype.catch 用于指定出錯(cuò)時(shí)的回調(diào),是特殊的then方法,catch之后,可以繼續(xù) .then

          Promise.prototype.catch?=?function?(onRejected)?{
          ????return?this.then(null,?onRejected);
          }

          Promise.prototype.finally

          不管成功還是失敗,都會(huì)走到finally中,并且finally之后,還可以繼續(xù)then。并且會(huì)將值原封不動(dòng)的傳遞給后面的then.

          Promise.prototype.finally?=?function?(callback)?{
          ????return?this.then((value)?=>?{
          ????????return?Promise.resolve(callback()).then(()?=>?{
          ????????????return?value;
          ????????});
          ????},?(err)?=>?{
          ????????return?Promise.resolve(callback()).then(()?=>?{
          ????????????throw?err;
          ????????});
          ????});
          }

          Promise.all

          Promise.all(promises) 返回一個(gè)promise對(duì)象

          1. 如果傳入的參數(shù)是一個(gè)空的可迭代對(duì)象,那么此promise對(duì)象回調(diào)完成(resolve),只有此情況,是同步執(zhí)行的,其它都是異步返回的。

          2. 如果傳入的參數(shù)不包含任何 promise,則返回一個(gè)異步完成.

          3. promises 中所有的promise都promise都“完成”時(shí)或參數(shù)中不包含 promise 時(shí)回調(diào)完成。

          4. 如果參數(shù)中有一個(gè)promise失敗,那么Promise.all返回的promise對(duì)象失敗

          5. 在任何情況下,Promise.all 返回的 promise 的完成狀態(tài)的結(jié)果都是一個(gè)數(shù)組

          Promise.all?=?function?(promises)?{
          ????promises?=?Array.from(promises);//將可迭代對(duì)象轉(zhuǎn)換為數(shù)組
          ????return?new?Promise((resolve,?reject)?=>?{
          ????????let?index?=?0;
          ????????let?result?=?[];
          ????????if?(promises.length?===?0)?{
          ????????????resolve(result);
          ????????}?else?{
          ????????????function?processValue(i,?data)?{
          ????????????????result[i]?=?data;
          ????????????????if?(++index?===?promises.length)?{
          ????????????????????resolve(result);
          ????????????????}
          ????????????}
          ????????????for?(let?i?=?0;?i???????????????????//promises[i]?可能是普通值
          ??????????????????Promise.resolve(promises[i]).then((data)?=>?{
          ????????????????????processValue(i,?data);
          ????????????????},?(err)?=>?{
          ????????????????????reject(err);
          ????????????????????return;
          ????????????????});
          ????????????}
          ????????}
          ????});
          }

          測試代碼:

          var?promise1?=?new?Promise((resolve,?reject)?=>?{
          ????resolve(3);
          })
          var?promise2?=?42;
          var?promise3?=?new?Promise(function(resolve,?reject)?{
          ??setTimeout(resolve,?100,?'foo');
          });

          Promise.all([promise1,?promise2,?promise3]).then(function(values)?{
          ??console.log(values);?//[3,?42,?'foo']
          },(err)=>{
          ????console.log(err)
          });

          var?p?=?Promise.all([]);?//?will?be?immediately?resolved
          var?p2?=?Promise.all([1337,?"hi"]);?//?non-promise?values?will?be?ignored,?but?the?evaluation?will?be?done?asynchronously
          console.log(p);
          console.log(p2)
          setTimeout(function(){
          ????console.log('the?stack?is?now?empty');
          ????console.log(p2);
          });

          Promise.race

          Promise.race函數(shù)返回一個(gè) Promise,它將與第一個(gè)傳遞的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失?。╮ejects),這要取決于第一個(gè)完成的方式是兩個(gè)中的哪個(gè)。

          如果傳的參數(shù)數(shù)組是空,則返回的 promise 將永遠(yuǎn)等待。

          如果迭代包含一個(gè)或多個(gè)非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將解析為迭代中找到的第一個(gè)值。

          Promise.race?=?function?(promises)?{
          ????promises?=?Array.from(promises);//將可迭代對(duì)象轉(zhuǎn)換為數(shù)組
          ????return?new?Promise((resolve,?reject)?=>?{
          ????????if?(promises.length?===?0)?{
          ????????????return;
          ????????}?else?{
          ????????????for?(let?i?=?0;?i?????????????????Promise.resolve(promises[i]).then((data)?=>?{
          ????????????????????resolve(data);
          ????????????????????return;
          ????????????????},?(err)?=>?{
          ????????????????????reject(err);
          ????????????????????return;
          ????????????????});
          ????????????}
          ????????}
          ????});
          }

          測試代碼:

          Promise.race([
          ????new?Promise((resolve,?reject)?=>?{?setTimeout(()?=>?{?resolve(100)?},?1000)?}),
          ????undefined,
          ????new?Promise((resolve,?reject)?=>?{?setTimeout(()?=>?{?reject(100)?},?100)?})
          ]).then((data)?=>?{
          ????console.log('success?',?data);
          },?(err)?=>?{
          ????console.log('err?',err);
          });

          Promise.race([
          ????new?Promise((resolve,?reject)?=>?{?setTimeout(()?=>?{?resolve(100)?},?1000)?}),
          ????new?Promise((resolve,?reject)?=>?{?setTimeout(()?=>?{?resolve(200)?},?200)?}),
          ????new?Promise((resolve,?reject)?=>?{?setTimeout(()?=>?{?reject(100)?},?100)?})
          ]).then((data)?=>?{
          ????console.log(data);
          },?(err)?=>?{
          ????console.log(err);
          });

          參考

          • Promise A+ 規(guī)范

          • ES6 Promise

          • Promise MDN

          學(xué)習(xí)交流

          • 關(guān)注公眾號(hào)【前端宇宙】,每日獲取好文推薦
          • 添加微信,入群交流

          “在看和轉(zhuǎn)發(fā)”就是最大的支持
          瀏覽 20
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩爽歪歪 | 人体模特小妮流水 | 先锋成人在线 | 北条麻美在线无码 | 日韩性爱一区 |