diff --git a/src/components/proxy/proxy-global.tsx b/src/components/proxy/proxy-global.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ab2679940ab272408a5e685932c9c27d49004e05
--- /dev/null
+++ b/src/components/proxy/proxy-global.tsx
@@ -0,0 +1,98 @@
+import { useEffect, useRef, useState } from "react";
+import { useSWRConfig } from "swr";
+import { useLockFn } from "ahooks";
+import { Virtuoso } from "react-virtuoso";
+import { Box, IconButton } from "@mui/material";
+import { MyLocationRounded, NetworkCheckRounded } from "@mui/icons-material";
+import { ApiType } from "../../services/types";
+import { updateProxy } from "../../services/api";
+import delayManager from "../../services/delay";
+import ProxyItem from "./proxy-item";
+
+interface Props {
+  groupName: string;
+  curProxy?: string;
+  proxies: ApiType.ProxyItem[];
+}
+
+const ProxyGlobal = (props: Props) => {
+  const { groupName, curProxy, proxies } = props;
+
+  const { mutate } = useSWRConfig();
+  const virtuosoRef = useRef<any>();
+  const [now, setNow] = useState(curProxy || "DIRECT");
+
+  const onChangeProxy = useLockFn(async (name: string) => {
+    await updateProxy("GLOBAL", name);
+    mutate("getProxies");
+    setNow(name);
+  });
+
+  const onLocation = (smooth = true) => {
+    const index = proxies.findIndex((p) => p.name === now);
+
+    if (index >= 0) {
+      virtuosoRef.current?.scrollToIndex?.({
+        index,
+        align: "center",
+        behavior: smooth ? "smooth" : "auto",
+      });
+    }
+  };
+
+  const onCheckAll = useLockFn(async () => {
+    // rerender quickly
+    if (proxies.length) setTimeout(() => mutate("getProxies"), 500);
+
+    let names = proxies.map((p) => p.name);
+    while (names.length) {
+      const list = names.slice(0, 8);
+      names = names.slice(8);
+
+      await Promise.all(list.map((n) => delayManager.checkDelay(n, groupName)));
+
+      mutate("getProxies");
+    }
+  });
+
+  useEffect(() => onLocation(false), [groupName]);
+
+  useEffect(() => {
+    if (groupName === "DIRECT") setNow("DIRECT");
+    if (groupName === "GLOBAL") setNow(curProxy || "DIRECT");
+  }, [groupName, curProxy]);
+
+  return (
+    <>
+      <Box sx={{ px: 3, my: 0.5 }}>
+        <IconButton
+          size="small"
+          title="location"
+          onClick={() => onLocation(true)}
+        >
+          <MyLocationRounded />
+        </IconButton>
+        <IconButton size="small" title="check" onClick={onCheckAll}>
+          <NetworkCheckRounded />
+        </IconButton>
+      </Box>
+
+      <Virtuoso
+        ref={virtuosoRef}
+        style={{ height: "calc(100% - 40px)" }}
+        totalCount={proxies.length}
+        itemContent={(index) => (
+          <ProxyItem
+            groupName={groupName}
+            proxy={proxies[index]}
+            selected={proxies[index].name === now}
+            onClick={onChangeProxy}
+            sx={{ py: 0, px: 2 }}
+          />
+        )}
+      />
+    </>
+  );
+};
+
+export default ProxyGlobal;
diff --git a/src/components/proxy/proxy-group.tsx b/src/components/proxy/proxy-group.tsx
index b620c6d55f0d0ab6c3fe6d469cb3b3de9abfa8eb..e52b01c0a2d840eb408d12ea91981cf9cef9a6f4 100644
--- a/src/components/proxy/proxy-group.tsx
+++ b/src/components/proxy/proxy-group.tsx
@@ -1,5 +1,6 @@
 import { useEffect, useRef, useState } from "react";
 import { useSWRConfig } from "swr";
+import { useLockFn } from "ahooks";
 import { Virtuoso } from "react-virtuoso";
 import {
   Box,
@@ -35,14 +36,10 @@ const ProxyGroup = ({ group }: Props) => {
   const virtuosoRef = useRef<any>();
   const proxies = group.all ?? [];
 
-  const selectLockRef = useRef(false);
-  const onSelect = async (name: string) => {
+  const onSelect = useLockFn(async (name: string) => {
     // Todo: support another proxy group type
     if (group.type !== "Selector") return;
 
-    if (selectLockRef.current) return;
-    selectLockRef.current = true;
-
     const oldValue = now;
     try {
       setNow(name);
@@ -50,8 +47,6 @@ const ProxyGroup = ({ group }: Props) => {
     } catch {
       setNow(oldValue);
       return; // do not update profile
-    } finally {
-      selectLockRef.current = false;
     }
 
     try {
@@ -73,7 +68,7 @@ const ProxyGroup = ({ group }: Props) => {
     } catch (err) {
       console.error(err);
     }
-  };
+  });
 
   const onLocation = (smooth = true) => {
     const index = proxies.findIndex((p) => p.name === now);
@@ -87,11 +82,7 @@ const ProxyGroup = ({ group }: Props) => {
     }
   };
 
-  const checkLockRef = useRef(false);
-  const onCheckAll = async () => {
-    if (checkLockRef.current) return;
-    checkLockRef.current = true;
-
+  const onCheckAll = useLockFn(async () => {
     // rerender quickly
     if (proxies.length) setTimeout(() => mutate("getProxies"), 500);
 
@@ -106,9 +97,7 @@ const ProxyGroup = ({ group }: Props) => {
 
       mutate("getProxies");
     }
-
-    checkLockRef.current = false;
-  };
+  });
 
   // auto scroll to current index
   useEffect(() => {
diff --git a/src/pages/proxies.tsx b/src/pages/proxies.tsx
index c95b447205569c99dc87049657602cb9b80cbb94..20f69359bc70e49fd4f9fff0d407eaa20cd0e597 100644
--- a/src/pages/proxies.tsx
+++ b/src/pages/proxies.tsx
@@ -1,90 +1,51 @@
 import useSWR, { useSWRConfig } from "swr";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { Virtuoso } from "react-virtuoso";
+import { useEffect } from "react";
+import { useLockFn } from "ahooks";
 import { Button, ButtonGroup, List, Paper } from "@mui/material";
-import { getClashConfig, updateConfigs, updateProxy } from "../services/api";
+import { getClashConfig, updateConfigs } from "../services/api";
 import { patchClashConfig } from "../services/cmds";
 import { getProxies } from "../services/api";
 import BasePage from "../components/base/base-page";
-import ProxyItem from "../components/proxy/proxy-item";
 import ProxyGroup from "../components/proxy/proxy-group";
+import ProxyGlobal from "../components/proxy/proxy-global";
 
 const ProxyPage = () => {
   const { mutate } = useSWRConfig();
   const { data: proxiesData } = useSWR("getProxies", getProxies);
   const { data: clashConfig } = useSWR("getClashConfig", getClashConfig);
-  const [curProxy, setCurProxy] = useState<string>("DIRECT");
-  const curMode = clashConfig?.mode.toLowerCase();
-
-  // proxy groups
-  const { groups = [] } = proxiesData ?? {};
-  // proxies and sorted
-  const filterProxies = useMemo(() => {
-    if (!proxiesData?.proxies) return [];
-
-    const list = Object.values(proxiesData.proxies);
-    const retList = list.filter(
-      (p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
-    );
-    const direct = list.filter((p) => p.name === "DIRECT");
-    const reject = list.filter((p) => p.name === "REJECT");
-
-    return direct.concat(retList).concat(reject);
-  }, [proxiesData]);
 
   const modeList = ["rule", "global", "direct"];
-  const asGroup = curMode === "rule" && groups.length;
+  const curMode = clashConfig?.mode.toLowerCase() ?? "direct";
+  const { groups = [], proxies = [] } = proxiesData ?? {};
 
   // make sure that fetch the proxies successfully
   useEffect(() => {
     if (
       (curMode === "rule" && !groups.length) ||
-      (curMode === "global" && filterProxies.length < 4)
+      (curMode === "global" && proxies.length < 2)
     ) {
       setTimeout(() => mutate("getProxies"), 500);
     }
-  }, [groups, filterProxies, curMode]);
-
-  // update the current proxy
-  useEffect(() => {
-    if (curMode === "direct") setCurProxy("DIRECT");
-    if (curMode === "global") {
-      const globalNow = proxiesData?.proxies?.GLOBAL?.now;
-      setCurProxy(globalNow || "DIRECT");
-    }
-  }, [curMode, proxiesData]);
+  }, [groups, proxies, curMode]);
 
-  const changeLockRef = useRef(false);
-  const onChangeMode = async (mode: string) => {
-    if (changeLockRef.current) return;
-    changeLockRef.current = true;
-
-    try {
-      // switch rapidly
-      await updateConfigs({ mode });
-      await patchClashConfig({ mode });
-      mutate("getClashConfig");
-    } finally {
-      changeLockRef.current = false;
-    }
-  };
-
-  const onChangeProxy = async (name: string) => {
-    if (curMode !== "global") return;
-    await updateProxy("GLOBAL", name);
-    setCurProxy(name);
-  };
+  const onChangeMode = useLockFn(async (mode: string) => {
+    // switch rapidly
+    await updateConfigs({ mode });
+    await patchClashConfig({ mode });
+    mutate("getClashConfig");
+  });
 
   // difference style
-  const pageStyle = asGroup ? {} : { height: "100%" };
-  const paperStyle: any = asGroup
+  const showGroup = curMode === "rule" && !!groups.length;
+  const pageStyle = showGroup ? {} : { height: "100%" };
+  const paperStyle: any = showGroup
     ? { mb: 0.5 }
     : { py: 1, height: "100%", boxSizing: "border-box" };
 
   return (
     <BasePage
       contentStyle={pageStyle}
-      title={asGroup ? "Proxy Groups" : "Proxies"}
+      title={showGroup ? "Proxy Groups" : "Proxies"}
       header={
         <ButtonGroup size="small">
           {modeList.map((mode) => (
@@ -101,26 +62,25 @@ const ProxyPage = () => {
       }
     >
       <Paper sx={{ borderRadius: 1, boxShadow: 2, ...paperStyle }}>
-        {asGroup ? (
+        {curMode === "rule" && !!groups.length && (
           <List>
             {groups.map((group) => (
               <ProxyGroup key={group.name} group={group} />
             ))}
           </List>
-        ) : (
-          // virtual list
-          <Virtuoso
-            style={{ height: "100%" }}
-            totalCount={filterProxies.length}
-            itemContent={(index) => (
-              <ProxyItem
-                groupName="GLOBAL"
-                proxy={filterProxies[index]}
-                selected={filterProxies[index].name === curProxy}
-                onClick={onChangeProxy}
-                sx={{ py: 0, px: 2 }}
-              />
-            )}
+        )}
+        {((curMode === "rule" && !groups.length) || curMode === "global") && (
+          <ProxyGlobal
+            groupName="GLOBAL"
+            curProxy={proxiesData?.global?.now}
+            proxies={proxies}
+          />
+        )}
+        {curMode === "direct" && (
+          <ProxyGlobal
+            groupName="DIRECT"
+            curProxy="DIRECT"
+            proxies={[proxiesData?.direct!].filter(Boolean)}
           />
         )}
       </Paper>
diff --git a/src/services/api.ts b/src/services/api.ts
index 844c5e3711533a0133d8203850593f8aeea5ae9e..751e56fd309e690fa25ffaa51197f88c283c8675 100644
--- a/src/services/api.ts
+++ b/src/services/api.ts
@@ -84,33 +84,41 @@ export async function updateProxy(group: string, proxy: string) {
 export async function getProxies() {
   const instance = await getAxios();
   const response = await instance.get<any, any>("/proxies");
-  const proxies = (response?.proxies ?? {}) as Record<
+  const records = (response?.proxies ?? {}) as Record<
     string,
     ApiType.ProxyItem
   >;
 
-  const global = proxies["GLOBAL"];
+  const global = records["GLOBAL"];
+  const direct = records["DIRECT"];
+  const reject = records["REJECT"];
   const order = global?.all;
 
   let groups: ApiType.ProxyGroupItem[] = [];
 
   if (order) {
     groups = order
-      .filter((name) => proxies[name]?.all)
-      .map((name) => proxies[name])
+      .filter((name) => records[name]?.all)
+      .map((name) => records[name])
       .map((each) => ({
         ...each,
-        all: each.all!.map((item) => proxies[item]),
+        all: each.all!.map((item) => records[item]),
       }));
   } else {
-    groups = Object.values(proxies)
+    groups = Object.values(records)
       .filter((each) => each.name !== "GLOBAL" && each.all)
       .map((each) => ({
         ...each,
-        all: each.all!.map((item) => proxies[item]),
+        all: each.all!.map((item) => records[item]),
       }));
     groups.sort((a, b) => b.name.localeCompare(a.name));
   }
 
-  return { global, groups, proxies };
+  const proxies = [direct, reject].concat(
+    Object.values(records).filter(
+      (p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
+    )
+  );
+
+  return { global, direct, groups, records, proxies };
 }