惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

M
MIT News - Artificial intelligence
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research
Last Week in AI
Last Week in AI
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
人人都是产品经理
人人都是产品经理
WordPress大学
WordPress大学
The Cloudflare Blog
IT之家
IT之家
雷峰网
雷峰网
小众软件
小众软件
博客园 - 叶小钗
博客园 - 聂微东
爱范儿
爱范儿
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
博客园 - 【当耐特】
V
V2EX
博客园_首页
T
Tailwind CSS Blog

Anthony Fu

Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony Fu Anthony's Roads to Open Source - The Set Theory (React ver.) Mental Health in Open Source The Evolution of Shiki v1.0 The Magic in Shiki Magic Move Anthony's Roads to Open Source - The Progressive Path Anthony Fu Anthony Fu Anthony Fu Anthony's Roads to Open Source - The Set Theory Now, and the Future of Nuxt Devtools Anthony's Roads to Open Source - The Set Theory Anthony Fu Anthony Fu Stable Diffusion QR Code 101 Refining AI Generated QR Code Stylistic QR Code with Stable Diffusion Anthony Fu How I Manage GitHub Notifications
Anthony Fu
Anthony Fu · 2021-07-01 · via Anthony Fu

async / await in ES7 is truly a life-saver for the JavaScript world. It allows you to avoid callback hell in your code and make it more readable. However, a common pitfall is that when you await a huge asynchronous task that takes very long time, it blocks the following code and could potentially make your app slow.

For example:

const app = await createServer()
const middlewareA = await resolveMiddlewareA()
const middlewareB = await resolveMiddlewareB()

app.use(middlewareA)
app.use(middlewareB)

We have used three await in the example, while the three async function does not actually relying on each other, having them sequentially we are possibility wasted some time of the operations that could be parallelized (IO, Network, etc.)

So we can use Promise.all to optimize the code:

const [app, middlewareA, middlewareB] = await Promise.all(
  [
    createServer(),
    resolveMiddlewareA(),
    resolveMiddlewareB(),
  ],
)

app.use(middlewareA)
app.use(middlewareB)

In another example, you might relying on the async result, but sometime not that urgent:

async function createPlugin() {
  const toolkit = await initToolKit()

  return {
    onHookA() {
      toolkit.invokeA()
    },
    onHookB() {
      toolkit.invokeB()
    },
  }
}

const plugin = await createPlugin()

Even though you don’t need toolkit immediately, you are still forced to use async function because the initToolKit is async. To avoid this, we could make the promise been resolved in the hooks instead

function createPlugin() {
  const toolkitPromise = initToolKit()

  return {
    async onHookA() {
      const toolkit = await toolkitPromise
      toolkit.invokeA()
    },
    async onHookB() {
      const toolkit = await toolkitPromise
      toolkit.invokeB()
    },
  }
}

// now it's sync!
const plugin = createPlugin()

Since a Promise could only be resolved once, using multiple await for a single Promise instance is totally fine - it will return the resolved result immediate if the Promise is allready settled.

To be more generalized, we could have an utility function like:

export function createSingletonPromise<T>(fn: () => Promise<T>) {
  let _promise: Promise<T> | undefined

  return () => {
    if (!_promise)
      _promise = fn()
    return _promise
  }
}

This function is also available in my utilities collection @antfu/utils