Frontend Development 17 min read

Practical Frontend Techniques: Vite Auto Routing, await-to-js Source Walkthrough, URL Parameter Handling, Controlling forEach Loops, and Singleton Request Management

This article presents practical frontend solutions, including automatic route generation in Vite projects using unplugin-vue-router, a detailed source analysis of the await‑to‑js error‑handling wrapper, methods for extracting URL parameters, techniques to terminate or replace forEach loops, and patterns for avoiding duplicate component requests.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Practical Frontend Techniques: Vite Auto Routing, await-to-js Source Walkthrough, URL Parameter Handling, Controlling forEach Loops, and Singleton Request Management

1. Vite Project Automatic Route Configuration

When developing a Vite project, adding a new page often requires manually updating the router, which can be tedious. Using the unplugin-vue-router plugin, developers can automatically generate route files for each .vue component.

1.1 Pain Points

Do you have to add a route entry every time you create a new page?

Would you like a .vue file to automatically generate its corresponding route?

Solution: install and configure unplugin-vue-router in vite.config.ts as shown below.

import VueRouter from 'unplugin-vue-router/vite'

export default defineConfig({
  plugins: [
    VueRouter({
      routesFolder: 'src/views',
      exclude: ['**/components/*.vue'],
      extensions: ['.vue']
    }),
    // ⚠️ Must be placed before Vue()
    Vue()
  ]
})

Additional configuration example:

VueRouter({
  routesFolder: 'src/pages',
  extensions: ['.vue'],
  exclude: [],
  dts: './typed-router.d.ts',
  routeBlockLang: 'json5',
  importMode: 'async'
})

Resulting folder structure:

src/views/
├── index.vue
├── about.vue
└── users.vue

Generated routes:

/ → renders index.vue

/about → renders about.vue

/users → renders users.vue

2. await-to-js Source Code Analysis

The library is described as an "Async await wrapper for easy error handling". It simplifies error handling by avoiding repetitive try/catch blocks when using async/await .

2.1 Usage

import to from 'await-to-js';

const [err, res] = await to(somePromise({ userId: 'demoId', name: 'demoName' }));
if (err) return console.error(err);
console.info(res);

The function always returns a two‑element array where the first element is the error (or null ) and the second is the result.

2.2 Source Walkthrough

/**
 * @param { Promise } promise
 * @param { Object= } errorExt - Additional information to merge into the error object
 * @return { Promise }
 */
export function to
(
  promise: Promise
,
  errorExt?: object
): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>(data => [null, data])
    .catch<[U, undefined]>(err => {
      if (errorExt) {
        const parsedError = Object.assign({}, err, errorExt);
        return [parsedError, undefined];
      }
      return [err, undefined];
    });
}
export default to;

Key points:

The function accepts a required Promise and an optional extra error object.

It always resolves to a length‑2 array: [error, result] .

Internally it uses then and catch to separate success and failure, optionally merging extra error info with Object.assign() .

3. Getting URL Parameters

3.1 Basic Retrieval

Given a URL like https://www.example.com?name=Tom&age=18&gender=male :

const search = window.location.search; // "?name=Tom&age=18&gender=male"
const params = new URLSearchParams(search);
const name = params.get('name'); // "Tom"
const age = params.get('age');   // "18"
const gender = params.get('gender'); // "male"

3.2 Edge Cases

If there are no query parameters, window.location.search returns an empty string.

Duplicate parameter names are merged; getAll() can retrieve all values.

Requesting a non‑existent key returns null .

3.3 Utility Function

A reusable function getUrlParams(url, key) returns the value or null :

function getUrlParams(url, key) {
  const search = new URL(url).search;
  const params = new URLSearchParams(search);
  return params.get(key);
}

const url = 'https://www.example.com?name=Tom&age=18&gender=male';
const name = getUrlParams(url, 'name'); // "Tom"
const hobby = getUrlParams(url, 'hobby'); // null

Further enhancements can support multiple keys, default values, or directly accept a URL object.

4. How to Terminate a forEach Loop

Because return and break do not stop a forEach , the following workarounds are shown:

4.1 Throw an Error

const array = [-3, -2, -1, 0, 1, 2, 3];
try {
  array.forEach(it => {
    if (it >= 0) {
      console.log(it);
      throw Error(`We've found the target element.`);
    }
  });
} catch (err) {
  // handle termination
}

4.2 Set Length to Zero

const array = [-3, -2, -1, 0, 1, 2, 3];
array.forEach(it => {
  if (it >= 0) {
    console.log(it);
    array.length = 0;
  }
});

4.3 Use splice to Remove Remaining Elements

const array = [-3, -2, -1, 0, 1, 2, 3];
array.forEach((it, i) => {
  if (it >= 0) {
    console.log(it);
    array.splice(i + 1, array.length - i);
  }
});

5. forEach Cannot Handle Asynchronous Tasks

5.1 Problem Demonstration

Using forEach with async functions leads to nondeterministic order because the loop does not await each promise.

async function processRoles() {
  let roles = ['admin', 'editor', 'employee'];
  roles.forEach(async role => {
    const result = await performTask(role);
    console.log(result);
  });
  console.log('All tasks dispatched');
}

function performTask(role) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`Processed role: ${role}`);
    }, Math.random() * 1000);
  });
}

processRoles();

Expected sequential output is often scrambled.

5.2 Solution: Use for…of

async function processRoles() {
  const roles = ['admin', 'editor', 'employee'];
  for (const role of roles) {
    const result = await performTask(role);
    console.log(result);
  }
  console.log('All tasks completed');
}

5.3 Using an Iterator Directly

Iterators expose value and done properties, allowing manual control of async sequencing.

let roles = ['admin', 'editor', 'employee'];
let iterator = roles[Symbol.iterator]();
let res = iterator.next();
while (!res.done) {
  console.log(res.value);
  console.log(await performTask(res.value));
  res = iterator.next();
}
console.log('All tasks completed');

6. Multiple Identical Component Duplicate Requests

When several identical components mount simultaneously, each may trigger the same API request, causing redundant network traffic. Two singleton‑based solutions are presented.

6.1 Simple Singleton with Cache

let cache = null;
let count = 0;

async function delay(ms = 200) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

export async function getSignature() {
  if (cache) return cache;
  if (count++) {
    while (!cache) await delay();
  } else {
    cache = await fetchSignature();
  }
  count--;
  return cache;
}

6.2 Asynchronous Singleton Pattern

Using a shared promise ( myfetch ) ensures that concurrent calls receive the same pending result.

function getSomething() {
  return new Promise(resolve => {
    const result = fetch('http://hn.algolia.com/api/v1/search?query=vue')
      .then(val => resolve(val.json()))
  })
}

let myfetch = null;
async function getData() {
  if (myfetch) return myfetch;
  myfetch = getSomething();
  try {
    const result = await myfetch;
    myfetch = null;
    return result;
  } catch (err) {
    console.error('err');
  }
}

const result1 = getData();
const result2 = getData();
const result3 = getData();
const result4 = getData();

console.log('123');
setTimeout(() => {
  console.log(result1, 'result1');
  console.log(result2, 'result2');
  console.log(result3, 'result3');
  console.log(result4, 'result4');
}, 1500);

All components receive the same resolved data without issuing multiple HTTP requests.

References

[1] https://cloud.tencent.com/developer/beta/article/1780993

frontendJavaScriptasyncvitesingletonforeachurl-params
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.