0%

In frontend interviews and daily development, Promise.race is a very common yet often overlooked API. Its rule is simple:

Multiple Promises “race” against each other—whichever settles first (fulfilled or rejected) determines the final result.

In this article, we will:

  • Clearly explain how Promise.race behaves and when to use it
  • Implement a custom myPromiseRace from scratch
  • Cover edge cases, optimizations, and common interview questions

1. What Is Promise.race?

Promise.race(iterable) accepts an iterable (usually an array) and returns a new Promise:

  • If any Promise fulfills first, the returned Promise fulfills
  • If any Promise rejects first, the returned Promise rejects
  • It does not wait for all Promises to finish
  • It does not cancel the remaining Promises—they continue running

2. Common Use Cases

2.1 Timeout Control (Most Common)

For example, treat a request as failed if it takes longer than 3 seconds:

  • fetch(url) vs timeoutPromise(3000)
  • Whichever finishes first determines the result

2.2 Multiple Data Sources (Fallback Strategy)

Fetch the same resource from multiple CDNs (CDN1/CDN2).
Use whichever responds first.

2.3 First-Render Racing

Load primary data, fallback data, and cached data simultaneously.
Render the page as soon as the fastest result arrives.

3. Implementing myPromiseRace

This implementation closely matches native behavior:

  • Validates that the input is iterable
  • Iterates over all inputs
  • Uses Promise.resolve to normalize non-Promise values
  • Resolves or rejects as soon as one Promise settles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function myPromiseRace(promises) {
return new Promise((resolve, reject) => {
// Validate iterable input
if (!promises || typeof promises[Symbol.iterator] !== 'function') {
return reject(new TypeError('Argument is not iterable'));
}

// Iterate over each Promise or value
for (const promise of promises) {
// Wrap with Promise.resolve to handle thenables and values
Promise.resolve(promise)
.then(resolve) // First fulfilled wins
.catch(reject); // First rejected wins
}
});
}

4. Key Insight: Why Use Promise.resolve?

The input to Promise.race does not have to be Promises. It may include:

  • Plain values: Promise.race([1, 2, 3])
  • Thenables: { then(resolve) { resolve(123) } }

Using Promise.resolve(x) ensures:

  • Plain values become immediately fulfilled Promises
  • Thenables are properly assimilated into the Promise chain

This behavior is consistent with the native Promise.race.

5. Handling Empty Iterables

Native Promise.race([]) returns a Promise that remains pending forever.

Your current implementation behaves the same way, since the loop never executes.
This matches the ECMAScript specification.

You could add explicit handling, but it’s not required.

6. Additional Test Cases

6.1 Rejection Wins First

1
2
3
4
5
6
7
const p1 = new Promise(res => setTimeout(() => res('p1'), 1000));
const p2 = new Promise(res => setTimeout(() => res('p2'), 500));
const p3 = new Promise((res, rej) => setTimeout(() => rej('p3 error'), 300));

myPromiseRace([p1, p2, p3])
.then(console.log)
.catch(console.error); // Output: p3 error

6.2 Plain Values Participate in the Race

1
2
3
4
5
6
7
8
9
myPromiseRace([
Promise.resolve('A'),
123,
new Promise(res => setTimeout(() => res('B'), 10))
])
.then(console.log)
.catch(console.error);

// Output: 123 (plain value wins immediately)

6.3 Empty Array Remains Pending

1
2
3
const p = myPromiseRace([]);
setTimeout(() => console.log('still pending...'), 1000);
// After 1 second: "still pending..."

7. Practical Example: Request Timeout with race

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms);
});
}

async function fetchWithTimeout(url, ms = 3000) {
return myPromiseRace([fetch(url), timeout(ms)]);
}

// Usage
fetchWithTimeout('https://example.com/api', 2000)
.then(res => res.json())
.then(data => console.log('data:', data))
.catch(err => console.error('error:', err.message));

8. Common Interview Questions (Bonus Points)

  • Q: Can Promise.race cancel the other Promises?
    No. Promises are not cancellable by default. Cancellation requires tools like AbortController or custom logic.

  • Q: What happens if you pass a plain value into race?
    It is wrapped by Promise.resolve and usually wins immediately.

  • Q: What’s the difference between race, any, and allSettled?

    • race: settles as soon as the first Promise settles
    • any: fulfills as soon as the first Promise fulfills (rejects only if all reject)
    • allSettled: waits for all Promises and returns their final states

9. Summary

The core idea behind implementing Promise.race can be summarized in one sentence:

Iterate over the iterable, wrap each item with Promise.resolve, attach the same resolve and reject, and let the first settled Promise decide the outcome.

In JavaScript, the new operator is a core concept that frequently appears in both interviews and everyday development.
Many developers use new regularly, but few truly understand what actually happens behind the scenes.

In this article, we’ll implement new by hand, breaking down its internal mechanics step by step to help you fully understand how JavaScript objects are created.

1. What Does the new Operator Actually Do?

When we execute the following line of code:

1
const person = new Person('Alice', 25);

JavaScript actually performs four steps internally:

  1. Create a new empty object
  2. Set the object’s prototype to the constructor’s prototype
  3. Execute the constructor and bind this to the new object
  4. If the constructor returns an object, return it; otherwise return the new object

Understanding these four steps is the key to understanding how new works.

2. Why Implement new Manually?

There are three main benefits to handwriting new:

  • Deepens your understanding of the prototype chain and this binding
  • It is a high-frequency frontend interview question
  • Helps you understand how frameworks create objects internally

Let’s jump straight into the code.

3. Handwriting the new Operator

1
2
3
4
5
6
7
8
9
10
11
function myNew(constructor, ...args) {
// 1. Create a new object and link its prototype
const obj = Object.create(constructor.prototype);

// 2. Execute the constructor with `this` bound to the new object
const result = constructor.apply(obj, args);

// 3. If the constructor returns an object, return it
// Otherwise, return the newly created object
return result instanceof Object ? result : obj;
}

This implementation fully reproduces the core behavior of the new operator.

4. Line-by-Line Breakdown

1. The Role of Object.create

1
const obj = Object.create(constructor.prototype);

This is equivalent to:

1
obj.__proto__ === constructor.prototype

Which means:

  • The new object can access methods on the constructor’s prototype
  • The prototype chain is properly established

2. constructor.apply(obj, args)

1
const result = constructor.apply(obj, args);

This step does two things:

  • Executes the constructor function
  • Binds this inside the constructor to the new object

So code like this:

1
2
this.name = name;
this.age = age;

Actually assigns properties directly to obj.

3. Why Do We Check the Return Value?

1
return result instanceof Object ? result : obj;

This is a detail many developers overlook.

Consider this example:

1
2
3
4
5
6
7
function Test() {
this.a = 1;
return { b: 2 };
}

const t = new Test();
console.log(t); // { b: 2 }

If a constructor explicitly returns an object, the new operator returns that object instead of this.

That’s why we must handle this case in our myNew implementation.

5. Testing Our myNew Function

1
2
3
4
5
6
7
8
9
10
function Person(name, age) {
this.name = name;
this.age = age;
}

const p1 = myNew(Person, 'Alice', 25);

console.log(p1.name); // Alice
console.log(p1.age); // 25
console.log(p1 instanceof Person); // true

The behavior matches native new perfectly.

6. Comparing myNew and Native new

Behavior new myNew
Create new object
Bind prototype
Bind this
Handle returned object

In practice, myNew reproduces about 90% of the real new operator’s behavior, which is more than sufficient for interviews and deep understanding.

7. Common Interview Follow-Up Questions

Q1: Why not simply use const obj = {}?

Because objects created with {} have their prototype set to Object.prototype.
Objects created with new must have their prototype set to the constructor’s prototype.

Q2: Can constructor.apply be replaced with call?

Yes. The only difference is how arguments are passed:

1
constructor.call(obj, ...args);

Q3: How does instanceof work?

1
p1 instanceof Person

Internally, JavaScript checks whether:

1
Person.prototype exists in p1’s prototype chain

8. Summary

  • The new operator is not magic—it follows a well-defined execution process
  • Handwriting new is one of the best ways to understand prototype chains, this, and constructors
  • Mastering this concept helps when learning Vue, React, and Node.js internals

If you can both write and explain this implementation,
90% of interviewers will consider your JavaScript fundamentals solid.

JavaScript Basics Summary (Hoisting, Strict Mode)


Rules for Variable and Function Hoisting

  • Variable hoisting: Execution still happens in order; variable declarations are hoisted but assignments are not.
  • Function hoisting: The entire function body is hoisted to the top of its scope.
  • Priority: Function hoisting > Variable hoisting.
1
2
3
4
5
6
7
console.log(a); // undefined
var a = 2;

foo(); // works normally
function foo() {
console.log("Function hoisting succeeded");
}

Using Strict Mode with use strict

What it does:

  • Prevents creating accidental global variables;
  • Disallows using undeclared variables, helping avoid memory leaks;
  • Binds this to undefined by default instead of window.
1
2
3
4
5
6
7
function foo() {
"use strict";
console.log(this.a); // ❌ TypeError
}

var a = 2;
foo(); // in strict mode, this is undefined, so this.a cannot be read

1
2
3
4
5
6
7
8
9
10
(function() {
"use strict";
foo(); // calling foo here doesn't change its default binding
})();

function foo() {
console.log(this.a);
}

var a = 2;

In web development, XSS (Cross-Site Scripting) is one of the most common and most dangerous security vulnerabilities.
Once a website contains an XSS flaw, attackers may execute malicious scripts in users’ browsers, allowing them to steal cookies, hijack sessions, deface pages, or even take over user accounts.

This article explains how to effectively defend against XSS attacks from both a theoretical and practical perspective, covering frontend and full-stack security best practices.

1. What Is an XSS Attack?

The essence of XSS is simple:

An attacker injects malicious JavaScript into a webpage, which is then executed in other users’ browsers.

Common types of XSS attacks include:

  • Reflected XSS: malicious scripts are delivered through URL parameters
  • Stored XSS: malicious scripts are stored in a database and served to users
  • DOM-based XSS: frontend JavaScript logic directly handles untrusted data

No matter the type, the root cause is the same:
👉 User input is treated as executable code.

2. Input Validation and Filtering (The Most Basic Defense)

Never trust user input.

1. Basic Frontend Validation

On the frontend, basic validation can improve user experience, such as:

  • Limiting input length
  • Enforcing input formats (e.g., email, phone numbers)
  • Filtering obviously dangerous characters

Example (for basic validation only):

1
2
3
function sanitizeInput(input) {
return input.replace(/[<>]/g, '');
}

⚠️ Important:
Frontend validation is not a security boundary and should never be relied on alone.

2. Strict Backend Validation (Critical)

Effective input validation must be performed on the server side:

  • Validate data types
  • Enforce length constraints
  • Reject inputs that violate business rules
  • Escape or sanitize HTML content using whitelists

Recommended principles:

  • Deny by default
  • Whitelist over blacklist

3. Output Encoding (More Important Than Input Filtering)

Many XSS vulnerabilities occur not because input is unsafe, but because output is handled incorrectly.

1. HTML Escaping on Output

When rendering user input, always encode HTML characters:

Character Escaped Form
< &lt;
> &gt;
" &quot;
' &#39;

Most modern template engines (Vue, React, Handlebars) escape output by default.
Do not disable this behavior unless absolutely necessary.

2. Avoid Dangerous APIs

Avoid patterns like:

1
element.innerHTML = userInput;

Safer alternatives include:

1
element.textContent = userInput;

Or:

1
2
3
const el = document.createElement('div');
el.textContent = userInput;
container.appendChild(el);

4. Use Safe APIs and Framework Protections

Modern frontend frameworks include built-in XSS protections.

1. Default Protections in React and Vue

  • JSX and template syntax escape output by default
  • Dangerous APIs are explicitly labeled (e.g., v-html, dangerouslySetInnerHTML)

⚠️ If you use these APIs, you must ensure the content is 100% trusted.

2. Avoid String-Based HTML Construction

❌ Unsafe example:

1
container.innerHTML = `<div>${userInput}</div>`;

✅ Safe alternative:

1
2
3
const div = document.createElement('div');
div.textContent = userInput;
container.appendChild(div);

5. Use Content Security Policy (CSP)

Content Security Policy (CSP) is one of the most powerful defenses against XSS.

1. What CSP Can Do

  • Block inline script execution
  • Restrict allowed script sources
  • Prevent loading malicious third-party resources

Example HTTP header:

1
2
3
4
Content-Security-Policy:
default-src 'self';
script-src 'self';
object-src 'none';

Even if an attacker injects a script, CSP can prevent the browser from executing it.

2. Why CSP Is So Important

Because it provides:

  • Browser-level protection
  • A strong fallback even when application code has flaws

6. Use HttpOnly and Secure Cookies

1. Purpose of HttpOnly

When setting cookies, add the HttpOnly flag:

1
Set-Cookie: sessionId=xxx; HttpOnly;

This prevents JavaScript from accessing cookies, reducing the impact of XSS attacks.

2. Combine with Secure and SameSite

For stronger protection, also use:

  • Secure
  • SameSite=Strict or Lax

This significantly improves session security.

7. Keep Third-Party Libraries Up to Date

In real-world projects, many XSS vulnerabilities come from third-party dependencies:

  • Outdated UI components
  • Unmaintained plugins
  • Vulnerable npm packages

Best practices:

  • Update dependencies regularly
  • Use npm audit
  • Monitor security advisories

8. Develop Secure Coding Habits

Preventing XSS is not about a single technique, but about consistent habits:

  • Never trust external input
  • Avoid innerHTML unless necessary
  • Do not ignore security warnings
  • Prioritize security over convenience

9. Summary

  • XSS is one of the most common and dangerous web security threats
  • Effective protection requires frontend, backend, and browser-level defenses
  • Input validation is only the beginning—safe output handling and CSP are critical
  • Good security habits are more valuable than any single patch

For frontend developers,
understanding how to prevent XSS is a key step toward true professionalism.

Installing Puppeteer on Baota (CentOS 8)

When using CentOS 8, yum may fail because CentOS 8 is no longer officially maintained.
To fix this, you need to switch the YUM mirror source, clear the cache, and rebuild it.

1. Replace the YUM repository source

1
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo

2. Clean YUM cache

1
sudo yum clean all

3. Rebuild YUM cache

1
sudo yum makecache

⚠️ Note:
CentOS 8 has reached End of Life (EOL) and is no longer maintained.
You must rely on third-party mirror sources to continue using yum.

Puppeteer Dependency Download Error

When installing Puppeteer, you may encounter errors while downloading Chromium dependencies.

You can refer to this article for details:
https://www.cnblogs.com/ilizhu/p/14504049.html

Puppeteer Sandbox Error

On some servers (such as Baota or other managed VPS environments), Puppeteer may fail to launch Chromium due to sandbox restrictions.

Solution: Disable sandbox when launching Puppeteer

1
2
3
4
// Add launch arguments to disable sandbox
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox']
});

Sync Google Sheets Data Across Multiple Sheets

There is a requirement to synchronize all sheets from one Google Spreadsheet to another spreadsheet (including all sub-sheets).

This is implemented using Google Sheets → Extensions → Apps Script.

Why synchronization is needed

The source spreadsheet is read-only by default.
By synchronizing its data into another spreadsheet, the copied sheets can then be edited freely.

sourceSpreadsheetId and targetSpreadsheetId are the IDs from the Google Sheets URL —
they are the long strings after /d/ in the address bar.

Apps Script Code Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function synchronizeSheetsToAnotherFile() {
const sourceSpreadsheetId = "id1";
const targetSpreadsheetId = "id2";
// Example: 1NOtSSvDwXrca8vqyZW6OqQJwGaCICMVguSz1-i72oqg

const sourceSpreadsheet = SpreadsheetApp.openById(sourceSpreadsheetId);
const targetSpreadsheet = SpreadsheetApp.openById(targetSpreadsheetId);

const sourceSheets = sourceSpreadsheet.getSheets();

sourceSheets.forEach(sheet => {
const sheetName = sheet.getName();
let targetSheet = targetSpreadsheet.getSheetByName(sheetName);

if (!targetSheet) {
targetSheet = targetSpreadsheet.insertSheet(sheetName);
} else {
targetSheet.clear();
}

const range = sheet.getDataRange();
const displayValues = range.getDisplayValues();
const formats = range.getBackgrounds();
const fontWeights = range.getFontWeights();

const targetRange = targetSheet.getRange(
1,
1,
displayValues.length,
displayValues[0].length
);

targetRange.setValues(displayValues);
targetRange.setBackgrounds(formats);
targetRange.setFontWeights(fontWeights);
});
}

  • Props and Callback Props:
    Used for parent–child component communication. Child components receive data from parents via props. Parents pass callback functions to children, and children invoke these callbacks to send data back to the parent.

  • Context API:
    An API for sharing state across components without the need to pass props down through every level of the component tree.

  • Redux or MobX:
    For complex applications, state management libraries can be used to handle communication and shared state between components.

  • Event Subscription Pattern:
    Uses mechanisms such as EventEmitter or third-party libraries to implement publish–subscribe patterns for communication between non-related components.

  • Hooks:
    Some React Hooks, such as useState, can be used to share logic and state between components through custom hooks.

Verbatim Teaching Script: “if-elif Conditional Statements”

    Students, just now the teacher noticed the class duty roster. From Monday to Friday, there are many diligent “little bees” on duty. I’d like to ask: which students are on duty on Monday? Please raise your hands. Yes, I see you. Now, students, do you remember who the students on duty on Monday are? That’s right, there are six students in total.

    Now suppose we take three classes as a unit and give you a student’s name. Can you quickly tell which day of the week this student is on duty? Do you have any good ideas? You there—yes, you mentioned memorizing it with a rhyme or mnemonic. Are there any better methods? You—right, we can use a program to output the result. So, what kind of statement should we use to represent multiple conditions? Today, we are going to learn another conditional statement in Python: if-elif-else.

    Next, please work in pairs with your desk mates. Analyze how to use if-elif-else to solve the problem of matching student names to duty days. You have 8 minutes. Begin.
Time’s up. While walking around, I saw everyone actively discussing. Which group would like to share your ideas? You, please. You said that we can input a student’s name and determine which day they are on duty by matching the name and outputting the corresponding weekday. Any additions? Group Five, please share. They suggested creating five arrays corresponding to Monday through Friday, placing each student’s name into the appropriate array, and then judging which day to output. That’s a very important point. Please sit down. Excellent work. It’s clear that everyone has previewed today’s lesson well.

    Next, let’s integrate everyone’s ideas. Please think independently and draw a flowchart. You have 5 minutes. Begin.
Time’s up. This student, please come up and present your flowchart. You explained that first we input the student’s name. If Xiaohua is in Monday’s array, then output Monday, and so on. Now, please try to write a multi-branch conditional statement. Here’s a hint from the teacher: use elif for additional conditional clauses. Let’s ask this student to write their answer on the blackboard. Students, compare it with your own code. Which parts need modification? You said the final elif should be changed to else, to indicate that when none of the conditions are met, the statements under else are executed. You also mentioned paying attention to indentation and colons. Very careful observations. I hope everyone writes carefully when coding. Now please use the if-elif statements you’ve learned to implement the algorithm you designed. I see that everyone has written it correctly and avoided the earlier issues.

    Now that we’ve written the statements, what is their execution process? Please discuss this in pairs. In a moment, we’ll ask one group to explain. You have 7 minutes. Begin.
I see students discussing quietly. Time’s up. Group Two, please explain the execution process. They used the flowchart to explain that the program checks each condition in order. If a condition is satisfied, it outputs the result; if none are satisfied, it outputs an error message. Their explanation combined diagrams and text and was very clear. Based on the flowchart on the screen, we can summarize the execution process of if-elif statements: the program starts from the if condition and checks conditions one by one. If a condition is true, the corresponding block of code is executed and the program exits the if structure. If the condition is false, it moves on to the next condition. If all conditions are false, the else block is executed.

    Now that we’ve finished learning the new knowledge, please write a complete program that implements this process. Students who finish early may think about real-life situations that require checking multiple conditions and write corresponding programs. Let’s invite some students to present their work. Some students approached the problem from a mathematics perspective, writing a program to compare three numbers and find the maximum. Others took inspiration from daily life and wrote a taxi fare calculation program. All of your programs were well-structured and correctly formatted.

    As today’s lesson comes to an end, what have you learned from this class? You said that you’ve learned the format and execution process of if-elif statements. It seems everyone has mastered today’s content. In fact, programming is very close to our daily life and studies, and it’s not as difficult as it may seem. The teacher hopes that you will continue to think actively and express your ideas in class just like today.

    Finally, here is a homework assignment: please compare the characteristics of the three types of if statements and organize them into a table.

    That’s all for today’s lesson. Goodbye, students.

  • Fabric: Enables synchronous UI rendering, eliminating the communication bottleneck of the Bridge.
  • TurboModules: Loads native modules on demand, improving app startup performance.
  • JSI (JavaScript Interface): Allows JavaScript to directly call native code, replacing the asynchronous Bridge. The Bridge is asynchronous and single-threaded, which introduces additional overhead; JSI, by contrast, is synchronous, lower-overhead, and supports concurrency.


The Next theme version used here is 7.8.0.

First, locate the file:

1
/themes/next/_config.yml

Search for the keyword font.
⚠️ Important: You must set enable inside font to true, because the default value is false.
If you only modify the family without enabling it, the font change will not take effect — so make sure you don’t miss this step.

If the font family is sourced from an external platform, you also need to configure the host.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
font:
enable: true

# Uri of fonts host, e.g. https://fonts.googleapis.com (Default).
host:

# Font options:
# `external: true` will load this font family from `host` above.
# `family: Times New Roman`. Without any quotes.
# `size: x.x`. Use `em` as unit. Default: 1 (16px)

# Global font settings used for all elements inside <body>.
global:
external: true
family: Noto Serif SC
size:

# Font settings for site title (.site-title).
title:
external: true
family: Noto Serif SC
size:

# Font settings for headlines (<h1> to <h6>).
headings:
external: true
family: Noto Serif SC
size:

# Font settings for posts (.post-body).
posts:
external: true
family: Noto Serif SC

# Font settings for <code> and code blocks.
codes:
external: true
family: Source Code Pro

Enable Copy Button for Code Blocks

In the same _config.yml file, locate the following configuration section.

Set copy_button.enable to true to enable the copy feature.

  • When show_result is set to true, a checkmark will be shown after copying.
  • The style option controls the appearance of the copy button. Choose based on your preference.
1
2
3
4
5
6
7
8
9
10
11
12
13
codeblock:
# Code Highlight theme
# Available values: normal | night | night eighties | night blue | night bright | solarized | solarized dark | galactic
# See: https://github.com/chriskempson/tomorrow-theme
highlight_theme: night eighties

# Add copy button on codeblock
copy_button:
enable: true
# Show text copy result.
show_result: true
# Available values: default | flat | mac
style: mac