溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

為什么重復(fù)的GET請(qǐng)求變慢了?

發(fā)布時(shí)間:2020-07-22 20:08:32 來(lái)源:網(wǎng)絡(luò) 閱讀:195 作者:Fundebug 欄目:web開(kāi)發(fā)

最近在研究慢請(qǐng)求監(jiān)控的問(wèn)題,寫(xiě)了一個(gè)簡(jiǎn)單的測(cè)試代碼:在網(wǎng)頁(yè)端(index.html)通過(guò)fetch函數(shù)向服務(wù)端獲取數(shù)據(jù),然后打印請(qǐng)求耗時(shí)。

function requestData() {
    let start = new Date();
    fetch("http://localhost:3000/company/basic")
        .then(res => {
            return res.json();
        })
        .then(res => {
            let span = new Date() - start;
            console.log("span:", span);
        });
}
requestData();

在服務(wù)端通過(guò)setTimeout延時(shí)1500s才返回?cái)?shù)據(jù)(服務(wù)端使用ExpressJS)。

app.get("/company/basic", (req, res) => {
    setTimeout(function() {
        res.send({ hello: "Hello Fundebug!" });
    }, 1500);
});

不出所料,span數(shù)據(jù)都略微大于 1500。

而后,我突發(fā)奇想,假設(shè)我同時(shí)發(fā)送多個(gè)請(qǐng)求會(huì)怎么樣呢?于是有了如下代碼:

[1, 2, 3].forEach(function() {
    requestData();
});

結(jié)果好像也沒(méi)問(wèn)題,在 Chrome 瀏覽器下面是這個(gè)效果:

為什么重復(fù)的GET請(qǐng)求變慢了?

接入 Fundebug 慢請(qǐng)求監(jiān)控測(cè)試

于是愉快地接入 Fundebug 監(jiān)控:

<script
    src="https://js.fundebug.cn/fundebug.1.9.0.min.js"
    apikey="API-KEY"
></script>

并設(shè)置如果請(qǐng)求時(shí)長(zhǎng)超過(guò) 2 秒就上報(bào):

if ("fundebug" in window) {
    fundebug.httpTimeout = 2000;
}

本以為刷新頁(yè)面,應(yīng)該不會(huì)收到報(bào)錯(cuò)。

結(jié)果,萬(wàn)萬(wàn)沒(méi)想到的是,F(xiàn)undebug 收到 2 個(gè)慢請(qǐng)求報(bào)錯(cuò)。

為什么重復(fù)的GET請(qǐng)求變慢了?

這不科學(xué)??!

點(diǎn)開(kāi)錯(cuò)誤詳情,可以看到具體的報(bào)錯(cuò)信息。一個(gè)請(qǐng)求耗時(shí) 3018 毫秒,一個(gè)請(qǐng)求耗時(shí) 4525 毫秒。

為什么重復(fù)的GET請(qǐng)求變慢了?

也就是說(shuō),第一個(gè)請(qǐng)求沒(méi)問(wèn)題,假設(shè)是 1500 毫秒。我們把三個(gè)請(qǐng)求的時(shí)間放一起看看有何規(guī)律:1500,3018,4524。他們近似成等差數(shù)列,相差 1500 毫秒。于是,我懷疑三個(gè)請(qǐng)求是一個(gè)一個(gè)阻塞式的,而不是并發(fā)的。

測(cè)試并發(fā)請(qǐng)求不同 API 的情況

為了驗(yàn)證這一點(diǎn),我將測(cè)試改為請(qǐng)求三個(gè)不同的 API 接口。

服務(wù)端代碼:

app.get("/company/basic", resp);
app.get("/company/basic1", resp);
app.get("/company/basic2", resp);

function resp(req, res) {
    setTimeout(function() {
        res.send({ hello: "Hello Fundebug!" });
    }, 1500);
}

網(wǎng)頁(yè)端代碼(requestData函數(shù)傳入請(qǐng)求的 URL):

[
    "http://localhost:3000/company/basic",
    "http://localhost:3000/company/basic1",
    "http://localhost:3000/company/basic2"
].forEach(function(item) {
    requestData(item);
});

為了獲取請(qǐng)求數(shù)據(jù),將httpTimeout改為 1500。

if ("fundebug" in window) {
    fundebug.httpTimeout = 1500;
}

Fundebug 捕獲三個(gè)請(qǐng)求的時(shí)間,分別為 1526,1525,1529。

為什么重復(fù)的GET請(qǐng)求變慢了?

至此大體驗(yàn)證了剛剛的假設(shè):對(duì)同一個(gè) API 接口的并發(fā)請(qǐng)求會(huì)被阻塞,對(duì)不同的 API 接口并發(fā)請(qǐng)求正常執(zhí)行。

那么為什么會(huì)被阻塞呢?意圖何在?接下來(lái)慢慢給各位介紹。

背后的原因

在StackOverflow上找到了答案:

Yes, this behavior is due to Chrome locking the cache and waiting to see the result of one request before requesting the same resource again. The answer is to find a way to make the requests unique.

也就是說(shuō),Chrome 特意做了這樣的設(shè)計(jì)。對(duì)于連續(xù)的相同請(qǐng)求,Chrome 會(huì)阻塞后面的請(qǐng)求,直到前面的完成。通過(guò)判斷前面的請(qǐng)求返回的 Header 里面的緩存設(shè)置來(lái)決定下一步的行動(dòng)。

我們可以做個(gè)實(shí)驗(yàn)來(lái)驗(yàn)證一下。

緩存實(shí)驗(yàn)

  • 服務(wù)端設(shè)置緩存 2 秒

    在服務(wù)端的接口返回代碼中配置緩存時(shí)間

    res.setHeader("Cache-Control", "public, max-age=2");

    為什么重復(fù)的GET請(qǐng)求變慢了?

  • 服務(wù)端設(shè)置不緩存

    res.setHeader(
      "Cache-Control",
      "private, no-cache, no-store, must-revalidate"
    );

    為什么重復(fù)的GET請(qǐng)求變慢了?

  • Chrome 開(kāi)發(fā)者面板設(shè)置Disable Cache

    為什么重復(fù)的GET請(qǐng)求變慢了?

最后的疑問(wèn)

為什么打開(kāi)和不打開(kāi)谷歌開(kāi)發(fā)者控制臺(tái),行為會(huì)不一樣了?

其實(shí)是有原因的,而且這個(gè)干擾項(xiàng)一度成功阻止了我發(fā)現(xiàn)問(wèn)題的本質(zhì)。當(dāng)我們?cè)陂_(kāi)發(fā)前端項(xiàng)目的時(shí)候,代碼的改動(dòng)希望能夠?qū)崟r(shí)地反應(yīng)到網(wǎng)頁(yè)上,而不是受到瀏覽器緩存的影響,但是我們發(fā)現(xiàn)往往刷新頁(yè)面的時(shí)候沒(méi)有真的去服務(wù)端獲取數(shù)據(jù),還是老的信息。于是,我們會(huì)去配置一個(gè)選項(xiàng),將Disable Cache設(shè)置為true。也就是說(shuō),在開(kāi)發(fā)環(huán)境下,緩存是被禁用了的,也就不存在等待第一個(gè)請(qǐng)求返回然后判斷其 Header 里面Cache-Control設(shè)置的問(wèn)題。這也是為什么打開(kāi)谷歌開(kāi)發(fā)者控制臺(tái),請(qǐng)求沒(méi)有等待,立即執(zhí)行了。

關(guān)于Fundebug

Fundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應(yīng)用實(shí)時(shí)BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計(jì)處理了10億+錯(cuò)誤事件,付費(fèi)客戶有陽(yáng)光保險(xiǎn)、核桃編程、荔枝FM、掌門(mén)1對(duì)1、微脈、青團(tuán)社等眾多品牌企業(yè)。歡迎大家免費(fèi)試用!

為什么重復(fù)的GET請(qǐng)求變慢了?

版權(quán)聲明

轉(zhuǎn)載時(shí)請(qǐng)注明作者 Fundebug以及本文地址:
https://blog.fundebug.com/2019/07/17/chrome-stall-multiple-same-request/

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI