Vue.js 2.0 foundation knowledge - modular development and advanced use of asynchronous programming
Article directory
- Vue.js 2.0 foundation knowledge - modular development and advanced use of asynchronous programming
- 1. Modular development
- 2. Promise
- 3. async/await
- 4. Event Loop
- 5. Macro tasks and micro tasks
- Six, API interface case
1. Modular development
Benefits of modular development: Everyone writes code following the same modular specification, which reduces communication costs and greatly facilitates mutual calls between modules
1.1 Classification of front-end modular development
Common modular specifications: CommonJS, AMD, CMD, and ES6 Modules , among which CommonJS, AMD, and CMD are modular standards proposed by the community, which have certain differences and limitations, and are not common to browsers and servers. Standards such as:
- AMD, CMD: JavaScript modularity for the browser
- CommonJS: JavaScript modularity for the server
1.2 CommonJS
node.js follows the CommonJS modular specification, and its core is import and export , among which:
- Import other modules using the require method
- The external shared members of the module use the module.export object
Import of CommonJS:
let {
flag, add} = require('moduleA');
// 等同于
let _mA = require('moduleA');
let flag = _mA.flag;
let add = _mA.add;
CommonJS export:
module.export = {
flag: true,
add(a, b) {
return a + b
}
}
1.3 ES6 modular specification
The ES6 modular specification is a modular development specification common to both the browser and the server. Developers do not need to learn additional modular specifications such as AMD, CMD or CommonJS.
The ES6 modular specification defines:
- Each JS file is an independent module
- To import other module members use the import keyword
- External shared module members use the export keyword
1.3.1 The basic syntax of ES6 modularization
ES6 modularity mainly includes 3 usages:
① Default export and default import
②On -demand export and on-demand import
③Directly import and execute the code in the module
1. Default export and default import
Default export syntax :export default 默认导出的成员
let n = 10;
let age = 20;
export default = {
n,
age
}
Default import syntax:import 接收名称 from '模块标识符'
import obj from './test.js'
Note: In each module, only one export default is allowed, otherwise an error will be reported
2. On-demand export and on-demand import
On-demand export syntax:export 按需导出的成员
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say() {
}
// 或者
let s1 = 'aaa'
let s2 = 'ccc'
function say() {
}
export {
s1, s2, say}
Import syntax on demand:import { 按需导入成员 } from '模块标识符'
import {
s1, s2 as str2 } from './test.js'
Notice:
- Multiple on-demand exports can be used in each module
- Member names imported on demand must be consistent with names exported on demand
- When importing on demand, you can use the as keyword to rename
- On-demand imports can be used with default imports
3. Directly import and execute the code in the module
If you just want to simply execute the code in the module , you don't need to get the externally shared members of the module. At this point, the module code can be directly imported and executed
// module.js
for(let i = 0; i < 3; i++) {
console.log(i);
}
// 其他模块中
// 直接导入并执行模块代码,不需要得到模块中向外共享的成员
import './module.js'
2. Promise
2.1 Read file content asynchronously based on then-fs
Since the fs module officially provided by node.js only supports reading files in the form of a callback function and does not support the calling method of Promise, the command needs to npm install then-fs
be support reading the content of the file based on the Promise method.
2.2 Basic use of then-fs
Call the readFile() method provided by then-fs to read the content of the file asynchronously, and its return value is the instance object of Promise . So you can call the .then() method to specify the success and failure callback functions for each Promise asynchronous operation.
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt', 'utf-8').then(r1 => {
console.log(r1); }, err1 => {
console.log(err1.message); });
thenFs.readFile('./files/2.txt', 'utf-8').then(r2 => {
console.log(r2); }, err2 => {
console.log(err2.message); });
thenFs.readFile('./files/3.txt', 'utf-8').then(r3 => {
console.log(r3); }, err3 => {
console.log(err3.message); });
Note: The above code cannot guarantee the order of reading files and needs further improvement!
2.3 Features of the .then() method
If a new Promise instance object is returned in the previous .then() method, you can continue processing through the next .then() method . The problem of callback hell can be solved by chaining calls of the .then() method.
2.4 Read the file content sequentially based on Promise
Promise supports chain calls, which can solve the problem that the above files are not read in order:
thenFs.readFile('./files/1.txt', 'utf-8')
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt', 'utf-8') // 在第一个 .then中返回一个新的 promise 实例对象
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf-8')
})
.then((r3) => {
console.log(r3)
})
2.5 Promise.all()
The Promise.all() method will initiate parallel Promise asynchronous operations, and the next .then operation (waiting mechanism) will not be executed until all asynchronous operations are completed . Sample code:
// 1.定义一个数组,存放3个读文件的异步操作
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf-8'),
thenFs.readFile('./files/2.txt', 'utf-8'),
thenFs.readFile('./files/3.txt', 'utf-8')
]
// 2.将 promise 数组作为promise.all()的参数
Promise.all(promiseArr)
.then(([r1, r2, r3]) => {
// 2.1 所有文件读取成功(等待机制)
console.log(r1, r2, r3)
})
.catch(err => {
// 2.2 捕获 Promise 异步操作中的错误
console.log(err.message)
})
Note: The order of the Promise instances in the array is the order of the final results
2.6 Promise-based encapsulation method for reading files
Method encapsulation requirements:
① The name of the method should be defined as getFile
② The method accepts a formal parameter fpath , indicating the path of the file to be read
③ The return value of the method is a Promise instance object
2.6.1 Basic definition of getFile method
function getFile(fpath) {
return new Promise() // 只是创建了形式上的异步操作
}
Note: new Promise() here just creates a formal asynchronous operation
2.6.2 Create specific asynchronous operations
If you want to create a specific asynchronous operation, you need to pass a function function during the new Promise() constructor to define the specific asynchronous operation inside the function function
function getFile(fpath) {
return new Promise(function() {
// 表明这是个具体的、读文件的异步操作
fs.readFile(fpath, 'utf-8',(err, data) => {
})
})
}
2.6.3 Get the two actual parameters of .then
The success and failure callback functions specified by .then() can be received in the formal parameters resolve and reject of the function. The sample code is as follows:
function getFile(fpath) {
return new Promise(function(resolve,reject) {
// 表明这是个具体的、读文件的异步操作
fs.readFile(fpath, 'utf-8',(err, data) => {
if(err) return reject(err)
resolve(data)
})
})
}
// getFile 方法调用
getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
3. async/await
3.1 The concept of async/await
async/await is a new syntax introduced by ES8 to simplify Promise asynchronous operations .
The method returns a Promise instance, which can be decorated with await. If the inner method is decorated with await, the outer method must be decorated with async
// 按照顺序读取文件 1、2、3 的内容
async function getAllFile() {
const r1 = await thenFS.readFile('./files/1.txt','utf8')
console.log(r1);
const r2 = await thenFS.readFile('./files/1.txt','utf8')
console.log(r2);
const r3 = await thenFS.readFile('./files/1.txt','utf8')
console.log(r3);
}
getAllFile()
Notice:
① If await is used in the function, the function must be modified by async
② In the async method, the code before the first await will be executed synchronously , and the code after await will be executed asynchronously
4. Event Loop
4.1 JavaScript is a single-threaded language
JavaScript is a single-threaded execution programming language, that is, only one thing can be done at a time. The problem of single-threaded execution task queue: If the previous task is very time-consuming, the subsequent task will have to wait forever, resulting in the problem of program suspended animation ,
4.2 Synchronous tasks and asynchronous tasks
In order to prevent the problem of program suspended animation caused by a time-consuming task , JavaScript divides the tasks to be executed into two categories:
① Synchronous task (synchronous)
- Also known as non-time-consuming tasks , they refer to those tasks that are queued for execution on the main thread
- The next task can only be executed after the previous task is completed
②Asynchronous task (asynchronous)
- Also called time-consuming tasks , asynchronous tasks are entrusted by JavaScript to the host environment (browser, node, etc.) for execution
- When the asynchronous task is executed, the JavaScript main thread will be notified to execute the callback function of the asynchronous task
4.3 The execution process of synchronous tasks and asynchronous tasks
① Synchronous tasks are executed sequentially by the JavaScript main thread
② Asynchronous tasks are delegated to the host environment for execution
③ The callback function corresponding to the completed asynchronous task will be added to the task queue for execution
④ After the execution stack of the JavaScript main thread is cleared, it will read the callback functions in the task queue and execute them sequentially
⑤ JavaScript main thread repeats step 4
4.4 The basic concept of EventLoop
The JavaScript main thread reads the callback function of the asynchronous task from the "task queue" and puts it in the execution stack for one execution . This process is cyclical, so the entire operating mechanism is also called EventLoop (event loop)
4.4.1 Combining EventLoop to analyze the output sequence (interview questions)
import thenFs from 'then-fs'
console.log('A')
thenFs.readFlie('./files/1.txt', 'utf8').then(data => {
console.log('B')
})
setTimeout(() => {
console.log('C')
}, 0)
console.log('D')
// A
// D
// C
// B
analyze:
- A and D are synchronous tasks and will be executed in sequence according to the sequence of codes
- C and B are asynchronous tasks . Their callback functions will be added to the task queue and wait for the main thread to be idle before executing
5. Macro tasks and micro tasks
JavaScript further divides asynchronous tasks, and asynchronous tasks are divided into two categories, namely:
① Macro task (macrotask)
- Asynchronous Ajax requests
- setTimeout、setInterval
- file operation
- other macro tasks
② Micro task (micro task)
- Promise.then、.catch 和 .finally
- Promise.nextTick
- other microtasks
5.1 Execution order of macrotasks and microtasks
- After each macrotask is executed, it will check whether there are microtasks to be executed . If so, after executing all microtasks, continue to execute the next macrotask
- When executing for the first time, when macro tasks and micro tasks exist at the same time, the micro tasks are executed first
5.2 Classical Interview Questions for Macro-tasks and Micro-tasks
Interview question 1: Analyze the sequence of the following code output
import thenFs from 'then-fs'
setTimeout(function() {
console.log('1')
})
new Promise(function(resolve) {
console.log('2')
resolve()
}).then(function() {
console.log('3')
})
console.log('4')
// 2
// 4
// 3
// 1
analyze:
- Execute all sync tasks first
- Re-execute the microtask
- Execute the macro task again
Interview question 2: Analyze the order of the following code output
console.log('1')
setTimeout(function() {
console.log('2')
new Promise(function(resolve) {
console.log('3')
resolve()
}).then(function() {
console.log('4')
})
})
new Promise(function(resolve) {
console.log('5')
resolve()
}).then(function() {
console.log('6')
})
setTimeout(function() {
console.log('7')
new Promise(function(resolve) {
console.log('8')
resolve()
}).then(function() {
console.log('9')
})
})
// 1
// 5
// 6
// 2
// 3
// 4
// 7
// 8
// 9
Six, API interface case
Case requirements: API interface service based on MySQL database + Express to provide external user list. The techniques used are as follows:
- Third-party packages express and mysql2
- ES6 Modularity
- Promise
- async/await
6.1 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
6.2 Build the basic structure of the project
① Enable ES6 modular support
- Declared in package.json
"type":"module"
② Install third-party dependent packages
- run
npm install [email protected] [email protected]
6.3 Create a basic express server
import express from 'express'
const app = express()
app.listen(80, () => {
console.log('server running at http://127.0.0.1:80');
})
6.4 Create db database operation module
import mysql from 'mysql2'
const pool = mysql.createPool({
host: '127.0.0.1',
port: 3306,
database: 'my_db_01', // 要操作的数据库名称
user: 'root',
password: 'admin123'
})
// 默认导出一个支持 Promise API 的 pool
export default pool.promise()
6.5 Create user_ctrl business module
// 获取所有用户的列表数据
import db from '../db/index.js'
// 按需导出
export async function getAllUser(req, res) {
// db.query() 函数的返回值时 Promise 的实例对象,因此可以使用async/await 进行简化
const [rows] = await db.query('select id, username, nickname from ev_users')
res.send({
status: 0,
message: '获取用户数据列表成功',
data: rows
})
}
6.6 Create user_router routing module
// user_router.js
import express from 'express'
// 从 user_ctrl.js 中按需导入 getAllUser 函数
import {
getAllUser } from '../controller/user_ctrl'
// 创建路由对象
const router = new express.Router()
// 挂载路由规则
router.get('/user', getAllUser)
export default router
6.7 Import and mount the routing module
//app.js
import express from 'express'
// 1.使用默认导入语法,导入路由对象
import userRouter from './router/user_router.js'
const app = express()
// 2. 挂载用户路由模块
app.use('/api', userRouter)
app.listen(80, () => {
console.log('server running at http://127.0.0.1:80');
})