es6导入导出
ES6 模块化规范中定义:
每个 js 文件都是一个独立的模块;
导入其它模块成员使用 import 关键字;
向外共享模块成员使用 export 关键字。
在 node.js 中使用 ES6 模块化
1.确保安装了 v14.15.1 或更高版本的 node.js;
2.在 package.json 的根节点中添加 "type": "module" 节点。
基本语法:
1. 默认导出与默认导入:
默认导出的成员:export default
每个模块中,只允许使用唯一的一次 export default
,否则会报错!
// 声明三个变量
let n1 = 100
let n2 = 200
let show = () => { console.log('show') }
// 默认导出语法 : export default 数据
export default {
n1,
show
}
默认导入的语法: import 接收名称 from '模块标识符
// es6的导入语法: omport xx form 路径
import m1 from "./m1.js"
console.log(m1) // { n1: 100, show: [Function: show] }
console.log(m1.n1) // 100
m1.show() // show
2. 按需导出与按需导入:
按需导出的语法: export 按需导出的成员
// 按需导出
export let s1 = 'aaa'
export let s2 = 'bbb'
export function say() {
console.log(say)
}
let user = {
name: 'jack',
age: 20
}
export default {
user
}
按需导入的语法: import { s1 } from '模块标识符'
// 按需导入
import user, { s1 as s, s2, say } from './m3.js'
console.log(s);
console.log(s2);
say()
// 可以使用as关键字修改变量名
// 按需导出导入可以和默认导出导入同时使用,默认导入的变量必须写在按需导入的前面并以逗号分割
console.log(user)
注意:
1. 每个模块中可以使用多次按需导出
2. 按需导入的成员名称必须和按需导出的名称保持一致
3. 按需导入时,可以使用 as 关键字进行重命名
4. 按需导入可以和默认导入一起使用
3. 直接导入并执行模块中的代码:
如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员。此时,可以直接导入并执行模块代码,示例代码如下:
for (let i = 0; i < 5; i++) {
console.log(i)
}
//-----------------分割线------------
// 直接导入执行某个模块中的代码,不需要得到模块中向外共享的成员
import './m5.js'
Promise
回调地狱:
多层回调函数的相互嵌套,就形成了回调地狱,如下代码:
import fs from 'fs'
fs.readFile('./files/1.txt', 'utf-8', (err, dataStr) => {
if (err) return console.log(err.message)
console.log(dataStr)
fs.readFile('./files/2.txt', 'utf-8', (err, dataStr) => {
if (err) return console.log(err.message)
console.log(dataStr)
fs.readFile('./files/3.txt', 'utf-8', (err, dataStr) => {
if (err) return console.log(err.message)
console.log(dataStr)
})
})
})
基本概念:
Promise可以解决回调地狱
1. promise是一个构造函数(new Promise),我们可以创建 Promise 的实例 const p = new Promise(),代表一个异步操作;
2. 构造函数中有一个实参,该实参是一个函数,当new时,该实参会立即执行;
3. new promise时,会返回一个实例p;
4. 实例p身上有一个方法then(在原型上),then方法有两个回调函数,第一个代表成功,第二个代表失败;成功是必选项,失败是可选项;
5. p.then(成功的回调函数,失败的回调函数),第一个成功的函数会赋值给resolve,第二个失败的函数会赋值给reject;
6. 有时then()失败的函数可以不写,用.catch来捕获错误;
7. promise.prototype中有then和catch,还有finally方法,不管成功失败都会执行。
创建具体的异步操作
基于promise读取文件:
import fs from 'fs'
const p = new Promise(function (resolve, reject) {
fs.readFile('./files/1.txt', 'utf-8', (err, dataStr) => {
if (err) return reject(err) //console.log(err.message)
resolve(dataStr) //console.log(dataStr)
})
})
获取 .then 的两个实参并调用resolve和reject
通过 .then() 指定的成功和失败的回调函数,可以在 function 的形参中进行接收,示例代码如下:
import fs from 'fs'
const p = new Promise(function (resolve, reject) {
fs.readFile('./files/1.txt', 'utf-8', (err, dataStr) => {
if (err) return reject(err) //console.log(err.message)
resolve(dataStr) //console.log(dataStr)
})
})
p.then(function (data) {
console.log(data)
}, function (err) {
console.log(err.message)
})
通过 .catch 捕获错误并使用finally(不管成功还是失败,都会执行)
import fs from 'fs'
const p = new Promise(function(resolve,reject){
// console.log(123);
fs.readFile("./files/11.txt",'utf-8',(err,dataStr)=>{
if(err) return reject(err);
resolve(dataStr)
})
})
// catch捕获错误
p.then(function(data){
console.log(data);
}).catch(function(err){
console.log(err.message);
}).finally(function(){
console.log("成功或失败都会执行");
})
使用promise封装ajax
<script>
// promise封装ajax
function ajax(){
return new Promise(function(resolve,reject){
// 以下就是ajax的异步操作
const xhr = new XMLHttpRequest()
xhr.open('get','http://www.liulongbin123.top:3009/api/getbooks')
xhr.send()
xhr.addEventListener("load",function(){
// console.log(xhr.response);
resolve(JSON.parse(xhr.response))
})
xhr.addEventListener("error",function(){
// console.log(err);
reject("出现错误了")
})
})
}
ajax().then(function(res){
console.log(res);
}).catch(function(err){
console.log(err);
})
// axios().then()
</script>
promise的静态方法
Promise.all()方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then操作(等待机制)。示例代码如下:
// 1.封装一个函数读取文件
import fs from 'fs'
function read(fpath){
let p = new Promise(function(resolve,reject){
fs.readFile(fpath,'utf-8',(err,dataStr)=>{
if(err) return reject(err)
resolve(dataStr)
})
})
return p
}
let p1 = read('./files/1.txt')
let p2 = read('./files/2.txt')
let p3 = read('./files/3.txt')
// let promiseArr = [p1,p2,p3]
// Promise.all() 当所有的promise异步操作执行完毕时,then方法中的函数才调用
Promise.all([p1,p2,p3]).then(([r1,r2,r3])=>{
console.log(r1);
console.log(r2);
console.log(r3);
})
Promise.race()方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)。示例代码如下:
// 1.封装一个函数读取文件
import fs from 'fs'
function read(fpath){
let p = new Promise(function(resolve,reject){
fs.readFile(fpath,'utf-8',(err,dataStr)=>{
if(err) return reject(err)
resolve(dataStr)
})
})
return p
}
let p1 = read('./files/1.txt')
let p2 = read('./files/2.txt')
let p3 = read('./files/3.txt')
// let promiseArr = [p1,p2,p3]
// Promise.race(): 竞赛 有一个promise异步操作执行完毕时,then方法中的结果是最先获取数据的结果
Promise.race([p1,p2,p3]).then((res)=>{
console.log(res);
})
async/await
说明:
async/await(es7)是异步操作的终极解决方案。
使用:
// 1. 异步函数返回值:永远返回的是一个promise实例
// 1.1 没有return 空promise没有太多实质意义
// 1.2 return非promise 将数据包装成了promise
// 1.3 return promise 返回的就是该promise
// 2.async/awiat 解决按需读取文件
// 注意: await后面跟promise实例
// async方法中,第一个await之前的代码会同步自行,之后的代码会异步执行。
console.log('a')
async function getFlie() {
console.log('b')
const p1 = await read('./files/1.txt')
const p2 = await read('./files/2.txt')
const p3 = await read('./files/3.txt')
console.log('c')
console.log(p1, p2, p3)
console.log('d')
}
console.log('e')
getFlie()
console.log('f')
// 打印的结果的顺序为:a e b f c 111 222 333 d
宏任务和微任务
JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。
eventloop:
为了防止某个耗时任务导致程序假死的问题,JavaScript 把待执行的任务分为了两类:
同步任务(synchronous)
又叫做非耗时任务,指的是在主线程上排队执行的那些任务;
只有前一个任务执行完毕,才能执行后一个任务。
异步任务(asynchronous)
又叫做耗时任务,异步任务由 JavaScript 委托给宿主环境进行执行;
当异步任务执行完成后,会通知 JavaScript 主线程执行异步任务的回调函数。
同步任务与异步任务的执行顺序
1.先执行同步任务,只有所有的同步任务执行完毕时,才执行执行异步任务;
2.什么是异步任务代码:
前端js
2.1 setTimeout setInterval
2.2 所有以on开头的事件 onclick onchange onblur ....
2.3 ajax中的 onload 代表数据从服务器成功的返回了
后端js
readFile() 读文件 ···
for(var i = 0; i<5; i++){
setTimeout(function(){
console.log(i);
},i*1000)
}
//结果: 5个5 全局变量i=5
for(let i = 0; i<5; i++){
setTimeout(function(){
console.log(i);
},i*1000)
}
//结果: 0 1 2 3 4 块级作用域
宏任务和微任务
JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
宏任务(macrotask)
异步 Ajax 请求、
setTimeout、setInterval、
文件操作
其它宏任务
微任务(microtask)
Promise.then、.catch 和 .finally
process.nextTick
其它微任务
宏任务和微任务的执行顺序:先主线程 再异步任务先微后宏
经典面试题
<script>
console.log(1)
setTimeout(function(){
console.log(2)
new Promise(function(resolve){
console.log(3)
resolve()
}).then(function(){
console.log(4)
})
},300)
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)
})
},500)
// 1 5 6 7 8 9 2 3 4
</script>