日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试题目_总结面试中 promise 相关题目的套路

發(fā)布時(shí)間:2023/12/2 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试题目_总结面试中 promise 相关题目的套路 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Promise 作為當(dāng)下主流的異步解決方案,在工作中和面試中常常出現(xiàn),尤其是在面試中,會(huì)弄個(gè)場景讓你手寫代碼,這里給大家介紹五道比較有代表性的題目,以便熟悉一些套路。

promise 簡單介紹

先簡單介紹下 Promise

Promise 對(duì)象用于表示一個(gè)異步操作的最終完成 (或失敗), 及其結(jié)果值。可以為異步操作的成功和失敗綁定執(zhí)行函數(shù),讓異步方法可以像同步方法一樣返回值,但立即返回的是一個(gè)能代表未來可能出現(xiàn)結(jié)果的Promise對(duì)象。

Promise 對(duì)象有三種狀態(tài):

  • pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
  • fulfilled: 意味著操作成功完成。
  • rejected: 意味著操作失敗。

Promise 的使用和提供的靜態(tài)方法:

  • new Promise( function(resolve, reject) {...} /* executor */ ); :返回 Promise 對(duì)象
  • Promise.all(iterable) :iterable參數(shù)對(duì)象里所有的promise對(duì)象都成功的時(shí)候才會(huì)觸發(fā)成功,若一個(gè)失敗,則立即觸發(fā)返回Promise對(duì)象的失敗
  • Promise.race(iterable):iterable參數(shù)中的一個(gè)成功或者失敗都會(huì)立即觸發(fā)返回對(duì)象的成功和失敗
  • Promise.reject(reason):返回一個(gè)狀態(tài)為失敗的Promise對(duì)象
  • Promise.resolve(value):返回一個(gè)狀態(tài)由value給定的Promise對(duì)象,通常用于將一個(gè)值以Promise的方式使用。

下面開始看題

題一

與js事件循環(huán)結(jié)合出題,如下,寫出執(zhí)行結(jié)果

console.log('script?start')
async?function?async1()?{
????await?async2()
????console.log('async1?end')
}
async?function?async2()?{console.log('async2?end')}
async1()
setTimeout(function?()?{console.log('setTimeout')},?0)
new?Promise(resolve?=>?{
????console.log('Promise')
????resolve()
}).then(function?()?{
????????console.log('promise1')
????}).then(function?()?{
????????console.log('promise2')
????})
console.log('script?end')
//?結(jié)果如下
//?script?start
//?async2?end
//?Promise
//?script?end
//?async1?end
//?promise1
//?promise2
//?setTimeout

掌握事件循環(huán)機(jī)制和明白 Promise.then() 屬于微隊(duì)列,這一類的題目就都是一個(gè)套路。

題二

實(shí)現(xiàn)如下調(diào)用,lazyMan('xxx').sleep(1000).eat('333').sleepFirst(2000) sleepFirst 最先執(zhí)行。

這題考察如何組合多個(gè) Promise 和鏈?zhǔn)秸{(diào)用。

可以用數(shù)組將 sleep eat 等函數(shù)暫存,同時(shí)為了能鏈?zhǔn)秸{(diào)用,所以每個(gè)函數(shù)需返回 Promise 對(duì)象。那么什么時(shí)候執(zhí)行數(shù)組中的函數(shù)呢?

根據(jù)事件循環(huán)機(jī)制,我們用 setTimeout 來執(zhí)行數(shù)組中的方法,在定時(shí)器的回調(diào)函數(shù)中相關(guān)的事件已經(jīng)添加到數(shù)組中了,鏈?zhǔn)綀?zhí)行數(shù)組中方法前,需要有一個(gè)構(gòu)建一個(gè) Promise 對(duì)象來執(zhí)行 then 方法,可以通過 Promise.resolve() 返回一個(gè) Promise 對(duì)象。

function?lazyMan(name)?{
????this.task?=?[];
????this.task.push(()?=>?{
????????return?new?Promise(res?=>?{
????????????console.log('name:'?+?name);res()
????????})
????})
????let?run?=?()?=>?{
????????let?sequence?=?Promise.resolve()
????????for?(const?func?of?this.task)?{
????????????sequence?=?sequence.then(()=>func())
????????}
????}
????setTimeout(()?=>?{run()},?0)
????this.eat?=?(str)?=>?{
????????this.task.push(()?=>?{
????????????return?new?(res?=>?{
????????????????console.log('eat:'?+?str);res()
????????????})
????????})
????????return?this;
????}
????this.sleep?=?(time)?=>?{
????????this.task.push(()?=>?{
????????????return?new?Promise(res?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log(`Wake?up?after?`?+?time);res()
????????????????},?time)
????????????})
????????})
????????return?this;
????}
????this.sleepFirst?=?(time)?=>?{
????????this.task.unshift(()?=>?{
????????????return?new?Promise(res?=>?{
????????????????setTimeout(()?=>?{
????????????????????console.log(`sleepFirst?up?after?`?+?time);res()
????????????????},?time)
????????????})
????????})
????????return?this;
????}
????return?this;
}

題三

任務(wù)隊(duì)列可不斷的添加異步任務(wù)(異步任務(wù)都是Promise),但只能同時(shí)處理5個(gè)任務(wù),5個(gè)一組執(zhí)行完成后才能執(zhí)行下一組,任務(wù)隊(duì)列為空時(shí)暫停執(zhí)行,當(dāng)有新任務(wù)加入則自動(dòng)執(zhí)行。

class?RunQune{
????constructor(){
????????this.list?=?[];?//?任務(wù)隊(duì)列
????????this.target?=?5;?//?并發(fā)數(shù)量
????????this.flag?=?false;?//?任務(wù)執(zhí)行狀態(tài)
????????this.time?=?Date.now()
????}
????async?sleep(time){
????????return?new?Promise(res=>setTimeout(res,time))
????}
????//?執(zhí)行任務(wù)
????async?run(){
????????while(this.list.length>0){
????????????this.flag?=?true;
????????????let?runList?=?this.list.splice(0,this.target);
????????????this.time?=?Date.now()
????????????await?this.runItem(runList)
????????????await?this.sleep(300)?//?模擬執(zhí)行時(shí)間
????????}
????????this.flag?=?false;
????}
????async?runItem(list){
????????return?new?Promise((res)=>{
????????????while(list.length>0){
????????????????const?fn?=?list.shift();
????????????????fn().then().finally(()=>{
????????????????????if(list.length?===?0){
????????????????????????res()
????????????????????}
????????????????})
????????????}
????????})
????}
????//?添加任務(wù)
????push(task){
????????this.list.push(...task);
????????!this.flag?&&?this.run()
????}
}

這題還可以進(jìn)一步發(fā)散,不需要等待一組完成在執(zhí)行下一組,只要并發(fā)量沒有滿,就可以加入新的任務(wù)執(zhí)行,實(shí)現(xiàn)的思路沒太大變化,在 finally 中改為新增任務(wù)。

題四

期望id按順序打印 0 1 2 3 4 ,且只能修改 start 函數(shù)。

function?start(id)?{
????execute(id)
}
for?(let?i?=?0;?i?5;?i++)?{
????start(i);
}
function?sleep()?{
????const?duration?=?Math.floor(Math.random()?*?500);
????return?new?Promise(resolve?=>?setTimeout(resolve,?duration));
}
function?execute(id)?{
????return?sleep().then(()?=>?{
????????console.log("id",?id);
????});
}

id 的打印是個(gè)異步事件,在 setTimeout 回調(diào)執(zhí)行,按照上面的代碼,誰的倒計(jì)時(shí)先結(jié)束,id就先打印,那么想要id按順序打印,就需要將多個(gè)異步事件同步執(zhí)行,promise 的鏈?zhǔn)秸{(diào)用可以派上用場。代碼如下

function?start(id)?{
????//?execute(id)
????//?第一種:promise 鏈?zhǔn)秸{(diào)用,execute 函數(shù)返回的就是 promise ,所以可以利用這一點(diǎn),通過 promise.then 依次執(zhí)行下一個(gè)打印
????this.promise?=?this.promise???this.promise.then(()=>execute(id))?:?execute(id)

????//?第二種:先用數(shù)組存儲(chǔ)異步函數(shù),利用事件循環(huán)的下一個(gè)階段,即 setTimeout 的回調(diào)函數(shù)中執(zhí)行 promise 的鏈?zhǔn)秸{(diào)用,這方法本質(zhì)上和第一種是一樣的
????this.list?=?this.list???this.list?:?[]
????this.list.push(()?=>?execute(id))
????this.t;
????if?(this.t)?clearTimeout(this.t)
????this.t?=?setTimeout(()?=>?{
????????this.list.reduce((re,?fn)?=>?re.then(()?=>?fn()),?Promise.resolve())
????})

????//?第三種:數(shù)組存儲(chǔ)id的值,在通過 await 異步執(zhí)行 execute 函數(shù)
????this.list?=?this.list???this.list?:?[]
????this.list.push(id)
????clearTimeout(this.t)
????this.t?=?setTimeout(async?()?=>?{
????????let?_id?=?this.list.shift()
????????while?(_id?!==?undefined)?{
????????????await?execute(_id);
????????????_id?=?this.list.shift()
????????}
????})
}

題五

手撕源碼系列,來手寫一個(gè)Promise,在動(dòng)手前需要先了解 Promise/A+ 規(guī)范,列舉關(guān)鍵部分的規(guī)范,詳細(xì)規(guī)范可見文末鏈接

  • Promise 的狀態(tài):一個(gè) Promise 的當(dāng)前狀態(tài)必須為以下三種狀態(tài)中的一種:等待態(tài)(Pending)、執(zhí)行態(tài)(Fulfilled)和拒絕態(tài)(Rejected)。
  • 狀態(tài)遷移:等待態(tài)可以遷移至執(zhí)行態(tài)或者拒絕態(tài);執(zhí)行態(tài)和拒絕態(tài)不能遷移至其他狀態(tài),且必須有一個(gè)不可變的終值
  • then 方法:一個(gè) promise 必須提供一個(gè) then 方法以訪問其當(dāng)前值、終值和據(jù)因,then 方法可以被同一個(gè) promise 調(diào)用多次。then 方法接收兩個(gè)參數(shù) onFulfilled, onRejected,onFulfilled 和 onRejected 必須被作為函數(shù)調(diào)用,且調(diào)用不可超過1次。then 方法需返回 Promise 對(duì)象
  • 根據(jù)這三點(diǎn)我實(shí)現(xiàn)了一個(gè)簡化版的 Promise

    function?MPromise(executor)?{
    ????this.status?=?'pending';?//?pending?,?fulfilled?,?rejected?
    ????this.data?=?''?//?當(dāng)前promise的值,主要用于?then?方法中的?fulfilled?,?rejected?兩種狀態(tài)的處理
    ????this.resolveFuncList?=?[];?//??使用數(shù)組的原因是,一個(gè)promise可以同時(shí)執(zhí)行多個(gè)?then?方法,?也就會(huì)同時(shí)存在多個(gè)then回調(diào)
    ????this.rejectFunc;
    ????const?self?=?this;
    ????function?resolve(value)?{
    ????????//?使用?setTimeout?實(shí)現(xiàn)異步
    ????????setTimeout(()?=>?{
    ????????????if?(self.status?===?'pending')?{
    ????????????????self.status?=?'fulfilled';
    ????????????????self.data?=?value;
    ????????????????//?執(zhí)行?resolve?函數(shù)
    ????????????????self.resolveFuncList.forEach(func?=>?{
    ????????????????????func(value)
    ????????????????});
    ????????????}
    ????????})
    ????}

    ????function?reject(reason)?{
    ????????setTimeout(()?=>?{
    ????????????if?(self.status?===?'pending')?{
    ????????????????self.status?=?'rejected';
    ????????????????self.data?=?value;
    ????????????????self.rejectFunc?&&?self.rejectFunc(reason);
    ????????????}
    ????????})
    ????}
    ????try?{
    ????????executor(resolve,?reject)
    ????}?catch?(error)?{
    ????????reject(error)
    ????}
    }

    MPromise.prototype.then?=?function?(onFulfilled,?onRejected)?{
    ????let?promise2;
    ????//?區(qū)分不同狀態(tài)下的處理
    ????if?(this.status?===?'pending')?{
    ????????return?promise2?=?new?MPromise((res,?rej)?=>?{
    ????????????this.resolveFuncList.push(function?(value)?{
    ????????????????let?x?=?onFulfilled(value);
    ????????????????resolvePromise(promise2,?x,?res,?rej)
    ????????????})

    ????????????this.rejectFunc?=?function?(reason)?{
    ????????????????let?x?=?onRejected(reason);
    ????????????????resolvePromise(promise2,?x,?res,?rej)
    ????????????}
    ????????})
    ????}
    ????if?(this.status?===?'fulfilled')?{
    ????????return?promise2?=?new?MPromise((res,?rej)?=>?{
    ????????????setTimeout(()?=>?{
    ????????????????let?x?=?onFulfilled(this.data)?//?輸出將上一次執(zhí)行結(jié)果
    ????????????????resolvePromise(promise2,?x,?res,?rej)
    ????????????})
    ????????})
    ????}
    ????if?(this.status?===?'rejected')?{
    ????????return?promise2?=?new?MPromise((res,?rej)?=>?{
    ????????????setTimeout(()?=>?{
    ????????????????let?x?=?onRejected(this.data)
    ????????????????resolvePromise(promise2,?x,?res,?rej)
    ????????????})
    ????????})
    ????}
    }

    function?resolvePromise(promise2,?x,?resolve,?reject)?{
    ????if?(x?instanceof?MPromise)?{
    ????????if?(x.status?===?'pending')?{
    ????????????x.then(value?=>?{
    ????????????????resolvePromise(promise2,?value,?resolve,?reject)
    ????????????},?reason?=>?{
    ????????????????reject(reason)
    ????????????})
    ????????}?else?{
    ????????????x.then(resolve,?reject)
    ????????}
    ????}?else?{
    ????????resolve(x)
    ????}
    }

    有的因?yàn)闀r(shí)間有限,會(huì)讓手寫 Promise 的 api,以下兩個(gè)就常常被問到

    1. 手寫一個(gè)?Promise.all

    /**
    ?*?Promise.all?Promise進(jìn)行并行處理
    ?*?參數(shù):?promise對(duì)象組成的數(shù)組作為參數(shù)
    ?*?返回值:?返回一個(gè)Promise實(shí)例
    ?*?當(dāng)這個(gè)數(shù)組里的所有promise對(duì)象全部進(jìn)入FulFilled狀態(tài)的時(shí)候,才會(huì)resolve。
    ?*/
    Promise.all?=?function(promises)?{
    ????return?new?Promise((resolve,?reject)?=>?{
    ????????let?values?=?[]
    ????????let?count?=?0
    ????????promises.forEach((promise,?index)?=>?{
    ????????????promise.then(value?=>?{
    ????????????????console.log('value:',?value,?'index:',?index)
    ????????????????values[index]?=?value
    ????????????????count++
    ????????????????if?(count?===?promises.length)?{
    ????????????????????resolve(values)
    ????????????????}
    ????????????},?reject)
    ????????})
    ????})
    }

    2. 手寫一個(gè) Promise.rase

    /**
    ?*?Promise.race
    ?*?參數(shù):?接收?promise對(duì)象組成的數(shù)組作為參數(shù)
    ?*?返回值:?返回一個(gè)Promise實(shí)例
    ?*?只要有一個(gè)promise對(duì)象進(jìn)入?FulFilled?或者?Rejected?狀態(tài)的話,就會(huì)繼續(xù)進(jìn)行后面的處理(取決于哪一個(gè)更快)
    ?*/
    Promise.race?=?function(promises)?{
    ????return?new?Promise((resolve,?reject)?=>?{
    ????????promises.forEach((promise)?=>?{
    ????????????promise.then(resolve,?reject);
    ????????});
    ????});
    }

    小結(jié)

    文中代碼略長,在電腦上查看效果更佳。

    若能幫到大伙,期望能給個(gè)點(diǎn)贊鼓勵(lì)~

    歡迎大伙在公號(hào)對(duì)話框點(diǎn)擊交個(gè)盆友,添加我微信一起探討交流~

    參考文章

    https://www.ituring.com.cn/article/66566?

    https://promisesaplus.com/

    總結(jié)

    以上是生活随笔為你收集整理的面试题目_总结面试中 promise 相关题目的套路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。