1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官:請(qǐng)手寫一個(gè)帶取消功能的延遲函數(shù),axios 取消功能的原理是什么

        共 9092字,需瀏覽 19分鐘

         ·

        2021-12-31 00:50

        本文倉庫 https://github.com/lxchuan12/delay-analysis.git,求個(gè)star^_^[1]

        源碼共讀活動(dòng) 每周一期,已進(jìn)行到17期。于是搜尋各種值得我們學(xué)習(xí),且代碼行數(shù)不多的源碼。delay 主文件僅70多行[2],非常值得我們學(xué)習(xí)。

        閱讀本文,你將學(xué)到:

        1.?學(xué)會(huì)如何實(shí)現(xiàn)一個(gè)比較完善的?delay?函數(shù)
        2.?學(xué)會(huì)使用?AbortController?實(shí)現(xiàn)取消功能
        3.?學(xué)會(huì)面試???axios?取消功能實(shí)現(xiàn)
        4.?等等

        2. 環(huán)境準(zhǔn)備

        #?推薦克隆我的項(xiàng)目,保證與文章同步
        git?clone?https://github.com/lxchuan12/delay-analysis.git
        #?npm?i?-g?yarn
        cd?delay-analysis/delay?&&?yarn?i
        #?VSCode?直接打開當(dāng)前項(xiàng)目
        #?code?.
        #?我寫的例子都在?examples?這個(gè)文件夾中,可以啟動(dòng)服務(wù)本地查看調(diào)試
        #?在?delay-analysis?目錄下
        npx?http-server?examples
        #?打開?http://localhost:8080

        #?或者克隆官方項(xiàng)目
        git?clone?https://github.com/sindresorhus/delay.git
        #?npm?i?-g?yarn
        cd?delay?&&?yarn?i
        #?VSCode?直接打開當(dāng)前項(xiàng)目
        #?code?.

        3. delay

        我們從零開始來實(shí)現(xiàn)一個(gè)比較完善的 delay 函數(shù)[3]。

        3.1 第一版 簡版延遲

        要完成這樣一個(gè)延遲函數(shù)。

        3.1.1 使用

        (async()?=>?{
        ????await?delay1(1000);
        ????console.log('輸出這句');
        })();

        3.1.2 實(shí)現(xiàn)

        PromisesetTimeout 結(jié)合實(shí)現(xiàn),我們都很容易實(shí)現(xiàn)以下代碼。

        const?delay1?=?(ms)?=>?{
        ????return?new?Promise((resolve,?reject)?=>?{
        ????????setTimeout(()?=>?{
        ????????????resolve();
        ????????},?ms);
        ????});
        }

        我們要傳遞結(jié)果。

        3.2 第二版 傳遞 value 參數(shù)作為結(jié)果

        3.2.1 使用

        (async()?=>?{
        ????const?result?=?await?delay2(1000,?{?value:?'我是若川'?});
        ????console.log('輸出結(jié)果',?result);
        })();

        我們也很容易實(shí)現(xiàn)如下代碼。傳遞 value 最后作為結(jié)果返回。

        3.2.2 實(shí)現(xiàn)

        因此我們實(shí)現(xiàn)也很容易實(shí)現(xiàn)如下第二版。

        const?delay2?=?(ms,?{?value?}?=?{})?=>?{
        ????return?new?Promise((resolve,?reject)?=>?{
        ????????setTimeout(()?=>?{
        ????????????resolve(value);
        ????????},?ms);
        ????});
        }

        這樣寫,Promise 永遠(yuǎn)是成功。我們也需要失敗。這時(shí)我們定義個(gè)參數(shù) willResolve 來定義。

        3.3 第三版 willResolve 參數(shù)決定成功還是失敗。

        3.3.1 使用

        (async()?=>?{
        ????try{
        ????????const?result?=?await?delay3(1000,?{?value:?'我是若川',?willResolve:?false?});
        ????????console.log('永遠(yuǎn)不會(huì)輸出這句');
        ????}
        ????catch(err){
        ????????console.log('輸出結(jié)果',?err);
        ????}
        })();

        3.3.2 實(shí)現(xiàn)

        加個(gè) willResolve 參數(shù)決定成功還是失敗。于是我們有了如下實(shí)現(xiàn)。

        const?delay3?=?(ms,?{value,?willResolve}?=?{})?=>?{
        ????return?new?Promise((resolve,?reject)?=>?{
        ????????setTimeout(()?=>?{
        ????????????if(willResolve){
        ????????????????resolve(value);
        ????????????}
        ????????????else{
        ????????????????reject(value);
        ????????????}
        ????????},?ms);
        ????});
        }

        3.4 第四版 一定時(shí)間范圍內(nèi)隨機(jī)獲得結(jié)果

        延時(shí)器的毫秒數(shù)是寫死的。我們希望能夠在一定時(shí)間范圍內(nèi)隨機(jī)獲取到結(jié)果。

        3.4.1 使用

        (async()?=>?{
        ????try{
        ????????const?result?=?await?delay4.reject(1000,?{?value:?'我是若川',?willResolve:?false?});
        ????????console.log('永遠(yuǎn)不會(huì)輸出這句');
        ????}
        ????catch(err){
        ????????console.log('輸出結(jié)果',?err);
        ????}

        ????const?result2?=?await?delay4.range(10,?20000,?{?value:?'我是若川,range'?});
        ????console.log('輸出結(jié)果',?result2);
        })();

        3.4.2 實(shí)現(xiàn)

        我們把成功 delay 和失敗 reject 封裝成一個(gè)函數(shù),隨機(jī) range 單獨(dú)封裝成一個(gè)函數(shù)。

        const?randomInteger?=?(minimum,?maximum)?=>?Math.floor((Math.random()?*?(maximum?-?minimum?+?1))?+?minimum);

        const?createDelay?=?({willResolve})?=>?(ms,?{value}?=?{})?=>?{
        ????return?new?Promise((relove,?reject)?=>?{
        ????????setTimeout(()?=>?{
        ????????????if(willResolve){
        ????????????????relove(value);
        ????????????}
        ????????????else{
        ????????????????reject(value);
        ????????????}
        ????????},?ms);
        ????});
        }

        const?createWithTimers?=?()?=>?{
        ????const?delay?=?createDelay({willResolve:?true});
        ????delay.reject?=?createDelay({willResolve:?false});
        ????delay.range?=?(minimum,?maximum,?options)?=>?delay(randomInteger(minimum,?maximum),?options);
        ????return?delay;
        }
        const?delay4?=?createWithTimers();

        實(shí)現(xiàn)到這里,相對(duì)比較完善了。但我們可能有需要提前結(jié)束。

        3.5 第五版 提前清除

        3.5.1 使用

        (async?()?=>?{
        ????const?delayedPromise?=?delay5(1000,?{value:?'我是若川'});

        ????setTimeout(()?=>?{
        ????????delayedPromise.clear();
        ????},?300);

        ????//?300?milliseconds?later
        ????console.log(await?delayedPromise);
        ????//=>?'我是若川'
        })();

        3.5.2 實(shí)現(xiàn)

        聲明 settle變量,封裝 settle 函數(shù),在調(diào)用 delayPromise.clear 時(shí)清除定時(shí)器。于是我們可以得到如下第五版的代碼。

        const?randomInteger?=?(minimum,?maximum)?=>?Math.floor((Math.random()?*?(maximum?-?minimum?+?1))?+?minimum);

        const?createDelay?=?({willResolve})?=>?(ms,?{value}?=?{})?=>?{
        ????let?timeoutId;
        ????let?settle;
        ????const?delayPromise?=?new?Promise((resolve,?reject)?=>?{
        ????????settle?=?()?=>?{
        ????????????if(willResolve){
        ????????????????resolve(value);
        ????????????}
        ????????????else{
        ????????????????reject(value);
        ????????????}
        ????????}
        ????????timeoutId?=?setTimeout(settle,?ms);
        ????});

        ????delayPromise.clear?=?()?=>?{
        ????????clearTimeout(timeoutId);
        ??timeoutId?=?null;
        ??settle();
        ????};

        ????return?delayPromise;
        }

        const?createWithTimers?=?()?=>?{
        ????const?delay?=?createDelay({willResolve:?true});
        ????delay.reject?=?createDelay({willResolve:?false});
        ????delay.range?=?(minimum,?maximum,?options)?=>?delay(randomInteger(minimum,?maximum),?options);
        ????return?delay;
        }
        const?delay5?=?createWithTimers();

        3.6 第六版 取消功能

        我們查閱資料可以知道有 AbortController 可以實(shí)現(xiàn)取消功能。

        caniuse AbortController[4]

        npm abort-controller[5]

        mdn AbortController[6]

        fetch-abort[7]

        fetch#aborting-requests[8]

        yet-another-abortcontroller-polyfill[9]

        3.6.1 使用

        (async?()?=>?{
        ????const?abortController?=?new?AbortController();

        ????setTimeout(()?=>?{
        ????????abortController.abort();
        ????},?500);

        ????try?{
        ????????await?delay6(1000,?{signal:?abortController.signal});
        ????}?catch?(error)?{
        ????????//?500?milliseconds?later
        ????????console.log(error.name)
        ????????//=>?'AbortError'
        ????}
        })();

        3.6.2 實(shí)現(xiàn)

        const?randomInteger?=?(minimum,?maximum)?=>?Math.floor((Math.random()?*?(maximum?-?minimum?+?1))?+?minimum);

        const?createAbortError?=?()?=>?{
        ?const?error?=?new?Error('Delay?aborted');
        ?error.name?=?'AbortError';
        ?return?error;
        };

        const?createDelay?=?({willResolve})?=>?(ms,?{value,?signal}?=?{})?=>?{
        ????if?(signal?&&?signal.aborted)?{
        ??return?Promise.reject(createAbortError());
        ?}

        ????let?timeoutId;
        ????let?settle;
        ????let?rejectFn;
        ????const?signalListener?=?()?=>?{
        ????????clearTimeout(timeoutId);
        ????????rejectFn(createAbortError());
        ????}
        ????const?cleanup?=?()?=>?{
        ??if?(signal)?{
        ???signal.removeEventListener('abort',?signalListener);
        ??}
        ?};
        ????const?delayPromise?=?new?Promise((resolve,?reject)?=>?{
        ????????settle?=?()?=>?{
        ???cleanup();
        ???if?(willResolve)?{
        ????resolve(value);
        ???}?else?{
        ????reject(value);
        ???}
        ??};

        ????????rejectFn?=?reject;
        ????????timeoutId?=?setTimeout(settle,?ms);
        ????});
        ????
        ????if?(signal)?{
        ??signal.addEventListener('abort',?signalListener,?{once:?true});
        ?}

        ????delayPromise.clear?=?()?=>?{
        ??clearTimeout(timeoutId);
        ??timeoutId?=?null;
        ??settle();
        ?};

        ????return?delayPromise;
        }

        const?createWithTimers?=?()?=>?{
        ????const?delay?=?createDelay({willResolve:?true});
        ????delay.reject?=?createDelay({willResolve:?false});
        ????delay.range?=?(minimum,?maximum,?options)?=>?delay(randomInteger(minimum,?maximum),?options);
        ????return?delay;
        }
        const?delay6?=?createWithTimers();

        3.7 第七版 自定義 clearTimeout 和 setTimeout 函數(shù)

        3.7.1 使用

        const?customDelay?=?delay7.createWithTimers({clearTimeout,?setTimeout});

        (async()?=>?{
        ????const?result?=?await?customDelay(100,?{value:?'我是若川'});

        ????//?Executed?after?100?milliseconds
        ????console.log(result);
        ????//=>?'我是若川'
        })();

        3.7.2 實(shí)現(xiàn)

        傳遞 clearTimeout, setTimeout 兩個(gè)參數(shù)替代上一版本的clearTimeout,setTimeout。于是有了第七版。這也就是delay的最終實(shí)現(xiàn)。

        ????const?randomInteger?=?(minimum,?maximum)?=>?Math.floor((Math.random()?*?(maximum?-?minimum?+?1))?+?minimum);

        const?createAbortError?=?()?=>?{
        ?const?error?=?new?Error('Delay?aborted');
        ?error.name?=?'AbortError';
        ?return?error;
        };

        const?createDelay?=?({clearTimeout:?defaultClear,?setTimeout:?set,?willResolve})?=>?(ms,?{value,?signal}?=?{})?=>?{
        ????if?(signal?&&?signal.aborted)?{
        ??return?Promise.reject(createAbortError());
        ?}

        ????let?timeoutId;
        ????let?settle;
        ????let?rejectFn;
        ????const?clear?=?defaultClear?||?clearTimeout;

        ????const?signalListener?=?()?=>?{
        ????????clear(timeoutId);
        ????????rejectFn(createAbortError());
        ????}
        ????const?cleanup?=?()?=>?{
        ??if?(signal)?{
        ???signal.removeEventListener('abort',?signalListener);
        ??}
        ?};
        ????const?delayPromise?=?new?Promise((resolve,?reject)?=>?{
        ????????settle?=?()?=>?{
        ???cleanup();
        ???if?(willResolve)?{
        ????resolve(value);
        ???}?else?{
        ????reject(value);
        ???}
        ??};

        ????????rejectFn?=?reject;
        ????????timeoutId?=?(set?||?setTimeout)(settle,?ms);
        ????});
        ????
        ????if?(signal)?{
        ??signal.addEventListener('abort',?signalListener,?{once:?true});
        ?}

        ????delayPromise.clear?=?()?=>?{
        ??clear(timeoutId);
        ??timeoutId?=?null;
        ??settle();
        ?};

        ????return?delayPromise;
        }

        const?createWithTimers?=?clearAndSet?=>?{
        ????const?delay?=?createDelay({...clearAndSet,?willResolve:?true});
        ????delay.reject?=?createDelay({...clearAndSet,?willResolve:?false});
        ????delay.range?=?(minimum,?maximum,?options)?=>?delay(randomInteger(minimum,?maximum),?options);
        ????return?delay;
        }
        const?delay7?=?createWithTimers();
        delay7.createWithTimers?=?createWithTimers;

        4. axios 取消請(qǐng)求

        axios取消原理是:通過傳遞 config 配置 cancelToken 的形式,來取消的。判斷有傳cancelToken,在 promise 鏈?zhǔn)秸{(diào)用的 dispatchRequest 拋出錯(cuò)誤,在 adapterrequest.abort() 取消請(qǐng)求,使 promise 走向 rejected,被用戶捕獲取消信息。

        更多查看我的 axios 源碼文章取消模塊 學(xué)習(xí) axios 源碼整體架構(gòu),取消模塊(可點(diǎn)擊)

        5. 總結(jié)

        我們從零開始實(shí)現(xiàn)了一個(gè)帶取消功能比較完善的延遲函數(shù)。也就是 delay 70多行源碼[11]的實(shí)現(xiàn)。

        包含支持隨機(jī)時(shí)間結(jié)束、提前清除、取消、自定義 clearTimeout、setTimeout等功能。

        取消使用了 mdn AbortController[12] ,由于兼容性不太好,社區(qū)也有了相應(yīng)的 npm abort-controller[13] 實(shí)現(xiàn) polyfill

        yet-another-abortcontroller-polyfill[14]

        建議克隆項(xiàng)目啟動(dòng)服務(wù)調(diào)試?yán)?,印象?huì)更加深刻。

        #?推薦克隆我的項(xiàng)目,保證與文章同步
        git?clone?https://github.com/lxchuan12/delay-analysis.git
        cd?delay-analysis
        #?我寫的例子都在?examples?這個(gè)文件夾中,可以啟動(dòng)服務(wù)本地查看調(diào)試
        npx?http-server?examples
        #?打開?http://localhost:8080


        參考資料

        [1]

        本文倉庫 https://github.com/lxchuan12/delay-analysis.git,求個(gè)star^_^: https://github.com/lxchuan12/delay-analysis.git

        [2]

        delay 主文件僅70多行: https://github.com/sindresorhus/delay/blob/main/index.js






        今日話題

        略。分享、收藏、點(diǎn)贊、在看我的文章就是對(duì)我最大的支持~
        瀏覽 56
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            人人插| 国内网友自拍操大码肥熟视频 | 亚洲色情电影 | 无码人妻精品一区二区二秋霞影院 | 99性爱视频 | 欧美激情三级 | 超碰97手机在线观看 | 精品欧美一区二区三区久久久 | 久久嫩草精品久久久久 | 操碰在线免费视频 |