慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
二微函数,令尔异步码成产用:`retry`与`timeout`
Daniel Keya · 2026-05-24 · via DEV Community

凡君所撰之异步函数,皆假以网络协从,伺应不爽,而数据库亦无颠踬。然于生产之际,此等假设永难恒持。

今有二阶函数,各不过十五行,可令任一异步函数坚韧,而无需触及其内里。


其弊在

尔有异步函数。或调用API,或查询数据库,或越网络读文件。

async function fetchUserData(userId) {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
}

Enter fullscreen mode Exit fullscreen mode

终有二事不谐:

  1. 时或失之,尔欲重试之
  2. 时或悬之无期,尔欲限时而弃之

尔可于每函数内嵌重试与超时之理。或一书写之,工致,而裹所欲之函数。


retry — 失败则自动重试

export function retry(count, callback) {
  return async function (...args) {
    let attempts = 0;
    let lastError;

    while (attempts <= count) {
      try {
        return await callback(...args);
      } catch (err) {
        lastError = err;
        attempts++;
      }
    }

    throw lastError;
  };
}

入全屏模式 出全屏模式

其运作之理

retry乃高阶函数,取一函数而返一嵌重试之新函数。原函数不损。

while (attempts <= count)之设,意有所在。若count3,则attempts时,循环乃行。0, 1, 2, 3 — 是谓四度戮之:初试一,复试三。此合乎"三度重试"之自然义。

若得,return await callback(...args) 即时而止,不复循环。若失,则谬误存于lastError,而attempts 渐增。及至试竭,乃抛最后之谬,非泛泛之咎。new Error('Max retries reached')者,实为回调所生之谬误也。调用者得义蕴之警示,非徒饰以囊括之。

用法

const resilientFetch = retry(3, fetchUserData);

// Works exactly like fetchUserData, but retries up to 3 times on failure
const user = await resilientFetch('user_123');

入全景模式 出全景模式

为何awaittry中要紧

try {
    return await callback(...args); // ✓ catches rejected promises
} catch (err) { ... }

入全景模式 出全景模式

无之await,弃之不允之诺,竟全脱试/捕之范围。

try {
    return callback(...args); // ✗ returns a pending promise — catch never fires
} catch (err) { ... }

入全景模式 出全屏模式

await启封于试块内之诺,故拒可捕。此乃异步/等待之常见谬误也。retry唯其得此正,故能效。


timeout— 逾期则弃

export function timeout(delay, callback) {
  return async function (...args) {
    const timer = new Promise((_, reject) =>
      setTimeout(() => reject(new Error('timeout')), delay)
    );

    return Promise.race([callback(...args), timer]);
  };
}

入全景模式 退出全屏模式

工作原理

Promise.race以首个解决之承诺为准,或成或败。此函数设一竞速之戏:

  • callback(...args)——实为之务
  • timer——一承诺,于delay毫秒后即败

。若回调及时完成,其值得胜,timer遂成虚设。若delay毫秒先逝。timer拒之Error('timeout')而回调之终局结果,亦所不顾也。

察计时器之承诺,乃所构建也(_, reject)— 永无决,唯拒。此可保计时器绝无偶得胜之机;惟可败而中断。

用之

const limitedFetch = timeout(5000, fetchUserData);

try {
    const user = await limitedFetch('user_123');
} catch (e) {
    if (e.message === 'timeout') {
        console.error('Request took too long');
    }
}

入全景模式 退出全屏模式


合而为一

二函数皆返异步函数,其签名为输入之同——是故可相合无碍.

// Retry up to 3 times, but abandon any single attempt after 5 seconds
const resilientFetch = retry(3, timeout(5000, fetchUserData));

await resilientFetch('user_123');

进入全屏模式 退出全屏模式

每试之状如下:

  1. timeout(5000, fetchUserData)以五秒之计时竞速于取物
  2. 若其超时,timeout 拒绝,Error('timeout')
  3. retry 捕捉此拒绝,增尝试之数,复试之。
  4. 三试皆败,retry 复抛末次之误。

四试,每试限五秒,总计至多二十秒。皆出二可组合之函数,一语而设。


何故值存此?

彼等不更其本函数。 fetchUserData 毫无更改。汝可随处用之,无论重试/超时与否。

彼等透明转发其引数。 ...args 皆通之,被裹之函数于调用者视之,无异于本函数。

彼等存其错。 retry 再抛之。lastError,非新异之误。timeout,拒以名目之Error('timeout'),可察于文。呼者恒知其故实。

,彼辈相成。,盖二皆返异步之函数,其签貌相合,故可层叠无序,相协无碍,互不知晓。


此法

二法同构:

higherOrderFn(config, callback) {
    return async function (...args) {
        // enhanced behaviour around callback(...args)
    }
}

入全屏模式 出全屏模式

此乃异步函数之裱花术。汝但书裱花一次,即可施诸需之异步函数——无承袭,无类,无改本。但见函数包函数耳。

此乃微纹也。一旦凝神细察,处处可见。