欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Promise面試題詳解之控制并發(fā)

 更新時間:2021年05月14日 11:43:50   作者:童紅雷  
promise面試中經(jīng)常會遇到的一個問題就是關(guān)于控制并發(fā)的,所以下面這篇文章主要給大家介紹了關(guān)于Promise面試題之控制并發(fā)的相關(guān)資料,需要的朋友可以參考下

前言

在寫這篇文章的時候我有點(diǎn)猶豫,因?yàn)橄惹皩戇^一篇類似的,一道關(guān)于并發(fā)控制的面試題,只不過那篇文章只給出了一種解決方案,后來在網(wǎng)上又陸續(xù)找到兩種解決方案,說來慚愧,研究問題總是淺嘗輒止,所以今天便放在一起,借著這道面試題再重新梳理一下。

題目是這樣的:

有 8 個圖片資源的 url,已經(jīng)存儲在數(shù)組 urls 中(即urls = [‘http://example.com/1.jpg', …., ‘http://example.com/8.jpg']),而且已經(jīng)有一個函數(shù) function loadImg,輸入一個 url 鏈接,返回一個 Promise,該 Promise 在圖片下載完成的時候 resolve,下載失敗則 reject。

但是我們要求,任意時刻,同時下載的鏈接數(shù)量不可以超過 3 個。

請寫一段代碼實(shí)現(xiàn)這個需求,要求盡可能快速地將所有圖片下載完成。

已有代碼如下:

var urls = [
'https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg', 
'https://www.kkkk1000.com/images/getImgData/gray.gif', 
'https://www.kkkk1000.com/images/getImgData/Particle.gif', 
'https://www.kkkk1000.com/images/getImgData/arithmetic.png', 
'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif', 
'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg', 
'https://www.kkkk1000.com/images/getImgData/arithmetic.gif', 
'https://www.kkkk1000.com/images/wxQrCode2.png'
];
function loadImg(url) {
    return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = function () {
            console.log('一張圖片加載完成');
            resolve();
        }
        img.onerror = reject
        img.src = url
    })
};

看到這個題目的時候,腦袋里瞬間想到了高效率排隊買地鐵票的情景,那個情景類似下圖:

上圖這樣的排隊和并發(fā)請求的場景基本類似,窗口只有三個,人超過三個之后,后面的人只能排隊了。

首先想到的便是利用遞歸來做,就如這篇文章采取的措施一樣,代碼如下:

//省略代碼

var count = 0;
//對加載圖片的函數(shù)做處理,計數(shù)器疊加計數(shù)
function bao(){
    count++;
    console.log("并發(fā)數(shù):",count)
    //條件判斷,urls長度大于0繼續(xù),小于等于零說明圖片加載完成
    if(urls.length>0&&count<=3){
    //shift從數(shù)組中取出連接
        loadImg(urls.shift()).then(()=>{
        //計數(shù)器遞減
            count--
            //遞歸調(diào)用
            }).then(bao)
    }
}
function async1(){
//循環(huán)開啟三次
    for(var i=0;i<3;i++){
        bao();
    }
}
async1()

以上是最常規(guī)的思路,我將加載圖片的函數(shù)loadImg封裝在bao函數(shù)內(nèi),根據(jù)條件判斷,是否發(fā)送請求,請求完成后繼續(xù)遞歸調(diào)用。

以上代碼所有邏輯都寫在了同一個函數(shù)中然后遞歸調(diào)用,可以優(yōu)化一下,代碼如下:

var count = 0;

// 封裝請求的異步函數(shù),增加計數(shù)器功能
function request(){
    count++;
    loadImg(urls.shift()).then(()=>{
            count--
            }).then(diaodu)

    
}
// 負(fù)責(zé)調(diào)度的函數(shù)
function diaodu(){
    if(urls.length>0&&count<=3){
        request();
    }
}

function async1(){
    for(var i=0;i<3;i++){
        request();
    }
}
async1()

上面代碼將一個遞歸函數(shù)拆分成兩個,一個函數(shù)只負(fù)責(zé)計數(shù)和發(fā)送請求,另外一個負(fù)責(zé)調(diào)度。

這里的請求既然已經(jīng)被封裝成了Promise,那么我們用Promise和saync、await來完成一下,代碼如下:

//省略代碼

// 計數(shù)器
var count = 0;
// 全局鎖
var lock = [];
var l = urls.length;
async function bao(){
    if(count>=3){
        //超過限制利用await和promise進(jìn)行阻塞;
        let _resolve;
        await new Promise((resolve,reject)=>{
            _resolve=resolve;
            // resolve不執(zhí)行,將其推入lock數(shù)組;
            lock.push(_resolve);
        });
    }
    if(urls.length>0){
        console.log(count);
        count++
        await loadImg(urls.shift());
        count--;
        lock.length&&lock.shift()()
    }
}
for (let i = 0; i < l; i++) {
    bao();
}

大致思路是,遍歷執(zhí)行urls.length長度的請求,但是當(dāng)請求并發(fā)數(shù)大于限制時,超過的請求用await結(jié)合promise將其阻塞,并且將resolve填充到lock數(shù)組中,繼續(xù)執(zhí)行,并發(fā)過程中有圖片加載完成后,從lock中推出一項(xiàng)resolve執(zhí)行,lock相當(dāng)于一個叫號機(jī);

以上代碼可以優(yōu)化為:

// 計數(shù)器
var count = 0;
// 全局鎖
var lock = [];
var l = urls.length;
// 阻塞函數(shù)
function block(){
    let _resolve;
    return  new Promise((resolve,reject)=>{
        _resolve=resolve;
        // resolve不執(zhí)行,將其推入lock數(shù)組;
        lock.push(_resolve);
    });
}
// 叫號機(jī)
function next(){
    lock.length&&lock.shift()()
}
async function bao(){
    if(count>=3){
        //超過限制利用await和promise進(jìn)行阻塞;
        await block();
    }
    if(urls.length>0){
        console.log(count);
        count++
        await loadImg(urls.shift());
        count--;
        next()
    }
}
for (let i = 0; i < l; i++) {
    bao();
}

最后一種方案,也是我十分喜歡的,思考好久才明白,大概思路如下:

用 Promise.race來實(shí)現(xiàn),先并發(fā)請求3個圖片資源,這樣可以得到 3 個 Promise實(shí)例,組成一個數(shù)組promises ,然后不斷的調(diào)用 Promise.race 來返回最快改變狀態(tài)的 Promise,然后從數(shù)組(promises )中刪掉這個 Promise 對象實(shí)例,再加入一個新的 Promise實(shí)例,直到全部的 url 被取完。

代碼如下:

//省略代碼
function limitLoad(urls, handler, limit) {
    // 對數(shù)組做一個拷貝
    const sequence = [].concat(urls)
    let promises = [];

    //并發(fā)請求到最大數(shù)
    promises = sequence.splice(0, limit).map((url, index) => {
        // 這里返回的 index 是任務(wù)在 promises 的腳標(biāo),
        //用于在 Promise.race 之后找到完成的任務(wù)腳標(biāo)
        return handler(url).then(() => {
            return index
        });
    });

    (async function loop() {
        let p = Promise.race(promises);
        for (let i = 0; i < sequence.length; i++) {
            p = p.then((res) => {
                promises[res] = handler(sequence[i]).then(() => {
                    return res
                });
                return Promise.race(promises)
            })
        }
    })()
}
limitLoad(urls, loadImg, 3)

第三種方案的巧妙之處,在于使用了Promise.race。并且在循環(huán)時用then鏈串起了執(zhí)行順序。

以上便是關(guān)于并發(fā)控制的一點(diǎn)點(diǎn)思考,有使用promise的,有不使用promise的,關(guān)鍵在于靈活運(yùn)用,通過這次梳理,你有哪些思考呢

總結(jié)

到此這篇關(guān)于Promise面試題詳解之控制并發(fā)的文章就介紹到這了,更多相關(guān)Promise控制并發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js opener的使用詳解

    js opener的使用詳解

    在JS中,window.opener只是對彈出窗口的母窗口的一個引用。本篇文章主要是對js中opener的使用進(jìn)行了詳細(xì)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • 如何在CocosCreator中使用JSZip壓縮

    如何在CocosCreator中使用JSZip壓縮

    這篇文章主要介紹了在CocosCreator中使用JSZip壓縮,對JSZip感興趣的同學(xué),不妨看一下,并且親自試一試
    2021-04-04
  • javascript搜索框點(diǎn)擊文字消失失焦時文本出現(xiàn)

    javascript搜索框點(diǎn)擊文字消失失焦時文本出現(xiàn)

    這篇文章主要介紹了javascript實(shí)現(xiàn)搜索框點(diǎn)擊文字消失失焦時文本出現(xiàn)的效果,示例代碼如下,大家可以看看
    2014-09-09
  • 一文詳解如何有效的處理Promise并發(fā)

    一文詳解如何有效的處理Promise并發(fā)

    這篇文章主要為大家介紹如何有效的處理Promise并發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 基于JavaScript實(shí)現(xiàn)幸運(yùn)抽獎頁面

    基于JavaScript實(shí)現(xiàn)幸運(yùn)抽獎頁面

    這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)幸運(yùn)抽獎頁面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • JavaScript實(shí)現(xiàn)簡單計時器

    JavaScript實(shí)現(xiàn)簡單計時器

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡單計時器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 超出JavaScript安全整數(shù)限制的數(shù)字計算BigInt詳解

    超出JavaScript安全整數(shù)限制的數(shù)字計算BigInt詳解

    這篇文章給大家分享了超出JavaScript安全整數(shù)限制的數(shù)字計算BigInt的相關(guān)知識點(diǎn),有興趣的朋友參考學(xué)習(xí)下。
    2018-06-06
  • JavaScript實(shí)現(xiàn)的背景自動變色代碼

    JavaScript實(shí)現(xiàn)的背景自動變色代碼

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)的背景自動變色代碼,涉及JavaScript數(shù)組操作結(jié)合定時函數(shù)實(shí)現(xiàn)修改頁面元素樣式的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • 微信小程序?qū)崿F(xiàn)簡易計算器

    微信小程序?qū)崿F(xiàn)簡易計算器

    這篇文章介紹了微信小程序?qū)崿F(xiàn)簡易計算器的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • 詳解微信小程序調(diào)用支付接口支付

    詳解微信小程序調(diào)用支付接口支付

    這篇文章主要介紹了微信小程序調(diào)用支付接口支付,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論