The source code for this blog is available on GitHub.
Note
Top

Real Life Scenario using JavaScript

Cover Image for Real Life Scenario using JavaScript
Han Chen
Han Chen

Abacus

Can you assist me in generating a series of arbitrary numbers in JavaScript with 2 decimal places? The series should consist of 2 numbers within the range of 0 to 10, 3 numbers between 10 and 100, and the remaining numbers should be within the range of 100 to 1000.

function generateArbitrarySeries() {
  let series = [];
  for (let i = 0; i < 10; i++) {
    let number;
    if (i < 2) {
      number = (Math.random() * 10).toFixed(2);
    } else if (i < 5) {
      number = (Math.random() * 90 + 10).toFixed(2);
    } else {
      number = (Math.random() * 900 + 100).toFixed(2);
    }
    series.push(parseFloat(number));
  }
  
  return series
}

console.log(series);

The answer should be like this

[ 9.61, 3.55, 31.09, 84.33, 81.84, 722.81, 827.06, 535.21, 789.24, 918.16 ]

Can you help me create a set of random numbers in JavaScript with 2 decimal places? The set should include 2 numbers between 0 and 10, 3 numbers between 10 and 100, and the rest of the numbers should be between 100 and 1000. Also, randomly select one number from each of the three groups (0 to 10, 10 to 100, 100 to 1000) and make it negative.

// ❌ sounds wrong
function generateSeriesWithNegativeNumber() {
  const series = [];
  let randomNum: number | string
  
  // generate 2 numbers within the range of 0 to 10
  for (let i = 0; i < 2; i++) {
    randomNum = (Math.random() * 10).toFixed(2);
    randomNum = Math.random() < 0.5 ? -randomNum : randomNum
    series.push(randomNum);
  }

  // generate 3 numbers between 10 and 100
  for (let i = 0; i < 3; i++) {
    randomNum = (Math.random() * 90 + 10).toFixed(2);
    randomNum = Math.random() < 0.5 ? -randomNum : randomNum;
    series.push(randomNum);
  }

  // generate remaining numbers within the range of 100 to 1000
  for (let i = 0; i < 5; i++) {
    randomNum = (Math.random() * 900 + 100).toFixed(2);
    randomNum = Math.random() < 0.5 ? -randomNum : randomNum;
    series.push(randomNum);
  }
  
  return series;
};

// ✅ seems right
function generateRandomNumbersWithNegativeNumber() {
  let numbers = [];

  // Generate 2 numbers between 0 and 10
  for (let i = 0; i < 2; i++) {
    numbers.push(Math.round((Math.random() * 10 + 1) * 100) / 100);
  }

  // Generate 3 numbers between 10 and 100
  for (let i = 0; i < 3; i++) {
    numbers.push(Math.round((Math.random() * 90 + 10) * 100) / 100);
  }

  // Generate the rest of the numbers between 100 and 1000
  for (let i = 0; i < 5; i++) {
    numbers.push(Math.round((Math.random() * 900 + 100) * 100) / 100);
  }

  // Randomly select one number from each group and make it negative
  numbers[Math.floor(Math.random() * 2)] *= -1;
  numbers[2 + Math.floor(Math.random() * 3)] *= -1;
  numbers[5 + Math.floor(Math.random() * 5)] *= -1;
  
  return numbers
}

The answer should be like this

[ -9.61, 3.55, 31.09, -84.33, 81.84, 722.81, 827.06, -535.21, 789.24, 918.16 ]

Can you also helps me to shuffle the series?

I can help you shuffle the series. One way to shuffle an array in JavaScript is to use the Fisher-Yates shuffle algorithm. Here's a modified version of your code that implements this algorithm:

function generateRandomNumbersWithNegativeNumber() {
  let numbers = [];

  // Generate 2 numbers between 0 and 10
  for (let i = 0; i < 2; i++) {
    numbers.push(Math.round((Math.random() * 10 + 1) * 100) / 100);
  }

  // Generate 3 numbers between 10 and 100
  for (let i = 0; i < 3; i++) {
    numbers.push(Math.round((Math.random() * 90 + 10) * 100) / 100);
  }

  // Generate the rest of the numbers between 100 and 1000
  for (let i = 0; i < 5; i++) {
    numbers.push(Math.round((Math.random() * 900 + 100) * 100) / 100);
  }

  // Randomly select one number from each group and make it negative
  numbers[Math.floor(Math.random() * 2)] *= -1;
  numbers[2 + Math.floor(Math.random() * 3)] *= -1;
  numbers[5 + Math.floor(Math.random() * 5)] *= -1;

  // Shuffle the array using the Fisher-Yates shuffle algorithm
  for (let i = numbers.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
  }

  return numbers;
}

The answer should be like

[ 
  639.49,
  467.08,
  50.75,
  267.75,
  -79.67,
  89.64,
  -819.94,
  2.36,
  316.72,
  -10.44 
]

What is Fisher-Yates shuffle algorithm

The Fisher-Yates shuffle is a randomization algorithm that can be used to shuffle an array or list in a random order. The algorithm works by iterating through the list from the last element to the first, and for each iteration, swapping the current element with a randomly selected element from the unshuffled portion of the list. This ensures that each element has an equal chance of appearing in any position in the shuffled list, and that the final order of the elements is truly random. The Fisher-Yates shuffle is an efficient algorithm with a time complexity of O(n), where n is the number of elements in the list.

There isn't any right or wrong way of how to use async function

import httpService from "@/services/httpService";
import { transformBigCommerceProductToOmnisend } from "@/utils/bigCommerce/transformProducts";
export const updateProduct = async (productID: string) => {
  const { data: products }: { data: Product.GetProductResponse[] } =
    await httpService.get("/api/bigCommerce/products");
  const transformedData = products.map((product) => {
    const transformation = transformBigCommerceProductToOmnisend(product);
    return transformation;
  });

  for (const product of transformedData) {
    if (product.productID === productID) {
      await httpService.put(`/api/omnisend/products/${productID}`, product);
    }
  }
};

for the for loop part. If it is written as the following, technically it is not wrong. Additionally, it may be faster than the previous code since it don't need to wait for each await in for loop

transformedData.forEach(async t => {
  if (product.productID === productID) {
      await httpService.put(`/api/omnisend/products/${productID}`, product);
    }
})

In the original code snippet, the for loop is using await to make sure that each request to update a product is completed before moving on to the next one. This ensures that the updates are processed sequentially.

However, in the modified code snippet that uses forEach instead of for loop, each request is sent asynchronously. This means that the requests will be sent without waiting for the previous request to complete. Therefore, the order in which the requests complete is not guaranteed to be the same as the order in which they were sent.

In some cases, it may be faster to use forEach instead of for loop because the requests can be sent in parallel. However, this approach should be used with caution, especially if the number of requests is large. Sending too many requests simultaneously can overwhelm the server and may result in errors or degraded performance.

To summarize, the original code snippet ensures that the requests are processed sequentially using await inside a for loop, while the modified code snippet sends requests asynchronously using forEach. The choice between the two approaches depends on the specific use case and the requirements of the system.

The following is an demonstration for showing the descripency discrepancy obviously by console.log method

async function processPromises() {
  const promises = [];

  for (let i = 1; i <= 100; i++) {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(i);
      }, 5000); // add a delay of 500 milliseconds
    });
    promises.push(promise);
  }

  // Using await inside the forEach loop
  promises.forEach(async (p) => {
    const result = await p;
    console.log(`forEach ${result}`);
  });

  // using for loop to make it processed sequentially
  for (const promise of promises) {
    const result = await promise;
    console.log(`for loop ${result}`);
  }
}

processPromises();

Wrapped in a function call processPromises and apply with parenthesis

Wrap the code inside a function called processPromises and apply it with parentheses.

Is it really matter if I don't put async and await as a pair

Another thing I want to mention is we don't really need to make async/await as a pair.

Sometimes I want to run the apis in the background. Those apis are important but the checkout process is far more important so i choose to run them backgrounded

Another thing I want to mention is that we don't really need to use async/await together as a pair. Sometimes, I want to run APIs in the background. While these APIs are important, the checkout process takes precedence, so I choose to run them in the background

In JavaScript, async/await is used to handle asynchronous operations. When you make an API request, it typically takes some time to complete, during which your code should not be blocked. You can use await to wait for the API response to be returned before proceeding with the rest of your code.

However, if you do not want to wait for the API response before proceeding with the rest of your code, you can omit the await keyword. This will allow your code to continue running while the API request is being processed in the background.

For example, consider the following code:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  console.log(data);
}

In this code, the await keyword is used to wait for the API response before proceeding with the console.log statement. If you remove the await keyword from either or both of the statements, the code will continue running while the API request is being processed in the background.

async function fetchData() {
  const response = fetch('https://api.example.com/data');
  const data = response.json();
  console.log(data);
}

console.log is meaningless here unless you want to see the promise object.

In this example, the console.log statement will log a Promise object instead of the actual data. This is because fetch and response.json() both return Promises that need to be resolved before the actual data can be obtained. By omitting the await keyword, the Promises are not being resolved before the console.log statement is executed, resulting in the Promise object being logged instead of the actual data.

In the second code example provided, where the await keyword is removed from both statements, the fetch() method and response.json() method will still return promises, but these promises are not being resolved before proceeding to the console.log() statement.

This means that the console.log() statement will be executed before the API response is received and processed, which could result in unexpected behavior if you try to access the data that has not yet been received.

Be careful when using this approach, as it may lead to unexpected behavior if the API response is not returned before the rest of your code is executed. Additionally, it is important to handle any errors that may occur during the API request, regardless of whether you are using await or not.

How Google v8 engine handle promise - Review

The Google V8 engine is an open-source JavaScript engine used by the Google Chrome browser and Node.js. When a Promise is created, it is added to the microtask queue, which is a queue of callbacks that should be executed as soon as possible, after the current task completes.

When a Promise is resolved or rejected, its corresponding callbacks (i.e., then() or catch()) are added to the end of the microtask queue. This means that if there are multiple callbacks waiting in the queue, they will be executed in the order they were added.

The microtask queue takes precedence over the task queue, which is a queue of tasks that are executed by the event loop. Tasks in the task queue are typically I/O operations, timers, or user events.

This means that when the engine is processing the event loop, it will always first process any microtasks that are waiting in the microtask queue, before moving on to any tasks in the task queue.

By using the microtask queue, the V8 engine can ensure that Promises are resolved in the correct order, and that their callbacks are executed as soon as possible, without blocking the main thread.

Here's an example

console.log('Start');

// Microtask queue
Promise.resolve().then(() => console.log('Promise 1'));
Promise.resolve().then(() => console.log('Promise 2'));

// Task queue
setTimeout(() => console.log('SetTimeout'), 0);
requestAnimationFrame(() => console.log('RequestAnimationFrame'));

console.log('End');

In this example, we have both a microtask queue and a task queue. The Promise.resolve() calls add two functions to the microtask queue. The setTimeout() and requestAnimationFrame() functions add two tasks to the task queue. Finally, we have two console.log() statements outside of any function, which are executed immediately.

When this code is executed, the output will be:

Start
End
Promise 1
Promise 2
RequestAnimationFrame
SetTimeout

Vocabulary

Some unfamiliar words pertaining to the article

takes precedence

"Takes precedence" means that something is more important or has a higher priority than something else. For example, in the sentence "During a fire evacuation, the safety of people takes precedence over saving property," it means that ensuring the safety of people is more important than trying to save property.

© 2024 WOOTHINK. All Rights Reserved.
Site MapTerms and ConditionsPrivacy PolicyCookie Policy