Node-es6导入导出、Promise、async/await、宏任务和微任务

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>

 


版权声明:本文为weixin_55847107原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。