05_01_vue01_ES6 modularity and asynchronous programming

ES6 Modularity

Basic concepts of modularization

Front-end modular classification

Before the birth of the ES6 modular specification, the JavaScript community had already tried and proposed modular specifications such as AMD, CMD, and CommonJS.

However, these modular standards proposed by the community still have certain differences and limitations, and are not universal modular standards for browsers and servers.

For example:

AMD and CMD for browser-side Javascript modularity

CommonJS for server-side Javascript modularization

Too many modular specifications increase learning difficulty and development costs for developers.

Therefore, the unified ES6 modular specification was born!

ES6 modular specification

The ES6 modular specification is a modular development specification common to both browser and server sides.

Its emergence has greatly reduced the modular learning cost of front-end developers. Developers no longer need to learn additional modular specifications such as AMD, CMD or CommonJS.

The ES6 modularity specification defines:

①Each js file is an independent module.

② Use the import keyword to import other module members.

③ Use the export keyword to share module members externally.

Experience ES6 modularity in node.js

Node.js follows the CommonJS modular specification.

in:

Import other modules using the require() method.

The module uses the module.exports object for external shared members.

Benefits of modularization: Everyone complies with the same modular specifications to write code, which reduces the cost of communication, greatly facilitates mutual calls between various modules, and benefits others and oneself.

By default, node.js only supports the CommonJS modular specification. If you want to experience and learn the modular syntax of ES6 based on node.js, you can configure it according to the following two steps:

① Make sure node.js v14.15.1 or higher is installed.

②Add the “type”: “module” node to the root node of package.json.

Basic syntax of ES6 modularity

Default export and default import

Syntax for default export: export default default exported members

Syntax for default import: import receives name from ‘module identifier’

Note:

① In each module, only export default is allowed to be used once, otherwise an error will be reported!

②The receiving name when importing by default can be any name, as long as it is a legal member name.

//Default export
let n1 = 10
let n2 = 20
function show() {}

export default {
  n1,
  show
}

// export default {
//n2
// }

//default import
import m1 from './01.Default export.js'
console.log(m1)

On-demand export and on-demand import

Syntax for export on demand: export Members exported on demand.

Syntax for on-demand import: import { s1 } from ‘module identifier’.

Note:

① Multiple on-demand exports can be used in each module.

②The name of the member imported on demand must be consistent with the name exported on demand.

③When importing on demand, you can use the as keyword to rename.

④On-demand import can be used together with default import.

// Export on demand
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say() {}

export default {
  a: 20
}

//Import on demand
import info, { s1, s2 as str2, say } from './03.Export on demand.js'

console.log(s1)
console.log(str2)
console.log(say)

console.log(info)

Directly import and execute the code in the module

If you just want to simply execute the code in a module, you don’t need to get the externally shared members in the module. At this point, the module code can be imported and executed directly.

//The current file is test.js
for (let i = 0; i < 3; i + + ) {
  console.log(i)
}

//Import the test.js file to execute the code
import './test.js'

Promise

Callback hell

The nesting of multiple layers of callback functions creates callback hell.

Disadvantages of callback hell:

①The code coupling is too strong, affecting the whole body, making it difficult to maintain.

② A large number of redundant codes are nested inside each other, making the code less readable.

Basic concepts of Promise

In order to solve the problem of callback hell, the concept of Promise was added in ES6 (ECMAScript 2015).

①Promise is a constructor.

We can create an instance of Promise const p = new Promise().

The Promise instance object produced by new represents an asynchronous operation.

②Promise.prototype contains a .then() method.

Each instance object obtained by the new Promise() constructor can access the .then() method through the prototype chain, such as p.then().

③.then() method is used to pre-specify success and failure callback functions.

p.then(success callback function, failure callback function) p.then(result => { }, error => { }).

When calling the .then() method, the success callback function is required and the failure callback function is optional.

Read file contents sequentially based on callback function

import thenFs from 'then-fs'

thenFs.readFile('./files/1.txt', 'utf8').then((r1) => {console.log(r1)})
thenFs.readFile('./files/2.txt', 'utf8').then((r2) => {console.log(r2)})
thenFs.readFile('./files/3.txt', 'utf8').then((r3) => {console.log(r3)})

Read file content based on then-fs

Since the fs module officially provided by node.js only supports reading files through callback functions, it does not support Promise calling methods.

Therefore, you need to run the following command first to install the then-fs third-party package to support us in reading the contents of the file based on Promise.

npm install then-fs

Call the readFile() method provided by then-fs to read the contents of the file asynchronously, and its return value is a Promise instance object. Therefore, you can call the .then() method to specify callback functions after success and failure for each Promise asynchronous operation.

[Note: The code cannot guarantee the reading order of files and needs further improvement! 】

Characteristics of .then() method

If a new Promise instance object is returned in the previous .then() method, processing can continue through the next .then() .

Through the chain call of .then() method, the problem of callback hell is solved.

import thenFs from 'then-fs'

thenFs.readFile('./files/1.txt', 'utf8').then((r1) => {console.log(r1)})
thenFs.readFile('./files/2.txt', 'utf8').then((r2) => {console.log(r2)})
thenFs.readFile('./files/3.txt', 'utf8').then((r3) => {console.log(r3)})

Read the contents of the file sequentially based on Promise

If an error occurs in the chain operation of Promise, you can use the Promise.prototype.catch method to capture and handle it.

If you don’t want the previous error to cause the subsequent .then to fail to execute normally, you can call .catch in advance.

import thenFs from 'then-fs'

thenFs
  .readFile('./files/11.txt', 'utf8')
  .catch((err) => {
    console.log(err.message)
  })
  .then((r1) => {
    console.log(r1)
    return thenFs.readFile('./files/2.txt', 'utf8')
  })
  .then((r2) => {
    console.log(r2)
    return thenFs.readFile('./files/3.txt', 'utf8')
  })
  .then((r3) => {
    console.log(r3)
  })

Promise.all() and Promise.race()

Promise.all() method

The Promise.all() method will initiate parallel Promise asynchronous operations, and wait until all asynchronous operations are completed before executing the next .then operation (waiting mechanism).

[Note: The order of Promise instances in the array is the order of the final results! 】

Promise.race() method

The Promise.race() method initiates parallel Promise asynchronous operations. As long as any asynchronous operation is completed, the next .then operation (race mechanism) will be executed immediately.

import thenFs from 'then-fs'

const promiseArr = [
  thenFs.readFile('./files/3.txt', 'utf8'),
  thenFs.readFile('./files/2.txt', 'utf8'),
  thenFs.readFile('./files/1.txt', 'utf8'),
]

// Promise.all(promiseArr).then((result) => {
// console.log(result);
// })

Promise.race(promiseArr).then(result => {
  console.log(result)
})

Method of encapsulating file reading based on Promise

Method encapsulation requirements:

①The name of the method should be defined as getFile.

②The method receives a formal parameter fpath, which represents the path of the file to be read.

③The return value of the method is a Promise instance object.

import fs from 'fs'

// 1. Define the getFile() method and receive the formal parameter fpath to represent the path of the file.
function getFile(fpath) {
  // 2. The return value of the method is a Promise instance object
  // Pass a function function and define specific asynchronous operations inside the function function
  // 4. The success and failure callback functions specified by .then() can be received in the formal parameters of the function
  return new Promise(function (resolve, reject) {
    // 3. This is an asynchronous operation to read a file
    fs.readFile(fpath, 'utf8', (err, dataStr) => {
      if (err) return reject(err) //Failed callback function
      resolve(dataStr) // Successful callback function
    })
  })
}

getFile('./files/11.txt')
  .then((r1) => {
    console.log(r1)
  })
  .catch((err) => console.log(err.message))

async/await

Basic concepts

async/await is a new syntax introduced in ES8 (ECMAScript 2017) to simplify Promise asynchronous operations.

Before the advent of async/await, developers could only handle Promise asynchronous operations through chained .then().

Advantages of .then chain calls: Solve the problem of callback hell.

Disadvantages of .then chain calls: code redundancy, poor readability, and difficult to understand.

Basic usage

①If await is used in function, the function must be modified with async.

②In the async method, the code before the first await will be executed synchronously, and the code after await will be executed asynchronously.

import thenFs from 'then-fs'

console.log('A')
async function getAllFile() {
  console.log('B')
  const r1 = await thenFs.readFile('./files/1.txt', 'utf8')
  console.log(r1)
  const r2 = await thenFs.readFile('./files/2.txt', 'utf8')
  console.log(r2)
  const r3 = await thenFs.readFile('./files/3.txt', 'utf8')
  console.log(r3)
  console.log('D')
}

getAllFile()
console.log('C') //Output result: A B 1 2 3 C D

EventLoop

JavaScript is a single-threaded programming language. In other words, you can only do one thing at a time.

Problems with single-threaded execution of task queues:

If the previous task is very time-consuming, subsequent tasks will have to wait, causing the program to hang.

[The JavaScript main thread reads the callback function of the asynchronous task from the “task queue” and puts it on the execution stack for execution in sequence.

This process is cyclical, so the entire operating mechanism is also called EventLoop. 】

Synchronous tasks and asynchronous tasks

In order to prevent a time-consuming task from causing the program to freeze, JavaScript divides the tasks to be executed into two categories:

Synchronous tasks (synchronous) are also called non-time-consuming tasks.

For those tasks queued for execution on the main thread, the next task can only be executed after the previous task has been executed.

②Asynchronous tasks (asynchronous) are also called time-consuming tasks.

Asynchronous tasks are delegated by JavaScript to the host environment for execution.

When the asynchronous task is completed, the JavaScript main thread will be notified to execute the callback function of the asynchronous task.

Macro tasks and micro tasks

Classic interview questions

API interface case

Based on MySQL database + Express, it provides an API interface service for user lists.

Main implementation steps:

① Build the basic structure of the project.

②Create a basic server.

③Create db database operation module.

④Create user_ctrl business module.

⑤Create user_router routing module.

① Build the basic structure of the project.

①Enable ES6 modular support.

Declare “type”: “module” in package.json to install third-party dependency packages

②Run npm install [email protected] [email protected].

②Create a basic server [./app.js].

import express from 'express'
const app = express()

app.listen(80, () => {
  console.log('server running at http://127.0.0.1')
})

③Create the db database operation module [./db/index.js].

import mysql from 'mysql2'

const pool = mysql.createPool({
  host: '127.0.0.1',
  port: 3306,
  database: 'my_db_01',
  user: 'root',
  password: 'admin123',
})

// What is exported is not the pool, but the return value of pool.promise()
export default pool.promise()

④Create the user_ctrl business module and use try…catch to catch exceptions [./controller/user_ctrl.js].

import db from '../db/index.js'

// Use the on-demand export syntax of ES6 to export the getAllUser method.
export async function getAllUser(req, res) {
  try {
    const [rows] = await db.query('select id, username, nickname, xxx from ev_users')
    res.send({
      status: 0,
      message: 'Getting user list data successfully! ',
      data: rows,
    })
  } catch (err) {
    res.send({
      status: 1,
      message: 'Failed to obtain user list data! ',
      desc: err.message,
    })
  }
}

⑤Create user_router routing module [./router/user_router.js].

import express from 'express'
import { getAllUser } from '../controller/user_ctrl.js'

const router = new express.Router()
router.get('/user', getAllUser)

export default router

⑥Import and mount the routing module [./app.js].

import express from 'express'
import userRouter from './router/user_router.js'
const app = express()

app.use('/api', userRouter)

app.listen(80, () => {
  console.log('server running at http://127.0.0.1')
})
syntaxbug.com © 2021 All Rights Reserved.