前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ES6模块化与异步编程

ES6模块化与异步编程

作者头像
小城故事
发布于 2023-04-03 01:45:23
发布于 2023-04-03 01:45:23
58400
代码可运行
举报
运行总次数:0
代码可运行

ES6 模块化

::: tip ES6 模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学习成本,开发者不需再额外学习 AMD、CMD 或 CommonJS 等模块化规范。

:::

ES6 模块化规范中定义:

  • 每个 js 文件都是一个独立的模块
  • 导入其它模块成员使用 import 关键字
  • 向外共享模块成员使用 export 关键字

ES6 的模块化3种用法

默认导出的语法: export default 默认导出的成员

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//01_test.js
// 定义成员和方法
let n1 = 10 
let n2 = 20
function show(){}

// 默认导出
export default{
    n1,
    n2,
    show
}

默认导入的语法:import 接收名称 from '模块标志符'

默认导入时的接收名称可以任意名称,只要是合法的成员名称即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 从 01_test.js 模块导入共享的成员
import test from './01_test.js'
// 输出 { n1:10,n2:20,show:[funtion:show] }
console.log(test)

每个模块中,只允许使用唯一的一次 export default,否则会报错!


按需导出的语法: export 按需导出的成员

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 02_test.js
// 向外按需导出变量 s1
export let s1 = 'abc'
// 向外按需导出变量 s2
export let s1 = 123
// 向外按需导出方法 say
export function say() {}

按需导入的语法: import { s1 } from '模块标识符'

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 导入 02_test.js 模块成员
import {s1,s2,say} from './02test.js'
// 输出 abc
console.log(s1)
// 输出 123
console.log(s2)
// 输出 [funtion:say]
console.log(say)

::: warning 注意事项

:::

  1. 每个模块中可以使用多次按需导出
  2. 按需导入的成员名称必须和按需导出的名称保持一致
  3. 按需导入时,可以使用 as 关键字进行重命名
  4. 按需导入可以和默认导入一起使用

::: tip

如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员。此时,可以直接导入并执行模块代码

:::

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 03_test.js

// 执行一个循环
for(let i = 0;i<3;i++){
    console.log(i)
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 导入
import './03_test.js'

// 直接运行此文件
// 输出 0,1,2,3,....10

Promise

回调地狱

多层回调函数的相互嵌套,就形成了回调地狱

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
setTimeout(() => {

	console.log("延迟1秒");

	setTimeout(() => {

		console.log("延迟2秒");

		setTimeout(() => {

			console.log("延迟2秒");

		}, 3000);

	}, 2000);
    
}, 1000);

回调地狱的缺点:

  • 代码耦合性太强,牵一发而动全身,难以维护
  • 大量冗余的代码相互嵌套,代码的可读性变差

::: tip

为了解决回调地狱的问题,ES6(ECMAScript 2015)中新增了 Promise 的概念。

:::

Promise 的基本概念

  1. Promise 是一个构造函数
    • 我们可以创建 Promise的实例 const p = ne w Promise()
    • new 出来的 Promise 实例对象,代表一个异步操作
  2. Promise.prototype 上包含一个 .then() 方法
    • 每一次 new Promise() 构造函数得到的实例对象,
    • 都可以通过原型链的方式访问到 .then() 方法,例如 p.then()
  3. .then() 方法用来预先指定成功和失败的回调函数
    • p.then(成功的回调函数,失败的回调函数)
    • p.then(result => { }, error => { })
    • 调用 .then() 方法时,成功的回调函数是必选的、失败的回调函数是可选的

基于回调函数按顺序读取文件内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fs from "fs";
// 读文件 1.txt
fs.readFile("./files/1.txt", "utf8", (err, r1) => {
	if (err) return console.log(err.message);
	console.log(r1);
	// 读文件 2.txt
	fs.readFile("./files/2.txt", "utf8", (err, r2) => {
		if (err) return console.log(err.message);
		console.log(r2);
		// 读文件 3.txt
		fs.readFile("./files/3.txt", "utf8", (err, r3) => {
			if (err) return console.log(err.message);
			console.log(r3);
		});
	});
});

调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此可以调用 .then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数

Promise 支持链式调用,从而来解决回调地狱的问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import thenFs from 'then-fs'
// Promise 支持链式调用,从而来解决回调地狱的问题
thenFs
	// 返回值是 promise 的实列对象
	.readFile("./files/1.txt", "utf8")
	// 通过 .then 为第一个 promise 实例对象指定成功后的回调函数
	.then((r1) => {
		console.log(r1);
		// 在第一个 .then 中返回一个新的 promise 对象
		return thenFs.readFile("./files/2.txt", "utf8");
	})
	// 继续调用 .then ,为上一个 .then 的返回值 (新的实例对象)
	// 指定成功后的回调函数
	.then((r2) => {
		console.log(r2);
		return thenFs.readFile("./files/3.txt", "utf8");
	})
	// 同理 继续调用 .then ,为上一个 .then 的返回值 (新的实例对象)
	.then((r3) => {
		console.log(r3);
	})
	// 通过 .catch 捕获错误
	// 前面的错误导致后续的 .then 无法正常执行
	// 可以将.catch 的调用提前
	.catch((err) => {
		console.log(err.message);
	});

Promise.all() 与 Promise.race() 方法

Promsie 方法

::: tip

Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then操作(等待机制)

:::

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import thenFs from "then-fs";
// 定义一个数组 存放异步读文件操作
const promiseArr = [
	thenFs.readFile("./files/1.txt", "utf8"),
	thenFs.readFile("./files/2.txt", "utf8"),
	thenFs.readFile("./files/3.txt", "utf8"),
];
// 将数组 作为 promise.all() 参数
Promise.all(promiseArr)
	.then(([r1, r2, r3]) => {
    // 所有文件读取成功 (等待机制)
    // 输出 r1 ,r2 ,r3 文件的内容
		console.log(r1, r2, r3);
	})
	.catch((err) => {
		console.log(err.message);
	});

// 数组中 Promise 实例的顺序,
// 就是最终结果的顺序!

::: tip

Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)

:::

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import thenFs from "then-fs";
// 定义一个数组 存放异步读文件操作
const promiseArr = [
	thenFs.readFile("./files/1.txt", "utf8"),
	thenFs.readFile("./files/2.txt", "utf8"),
	thenFs.readFile("./files/3.txt", "utf8"),
];
// 将数组 作为 promise.race() 参数
Promise.race(promiseArr)
	.then((results) => {
    // 只要任何一个异步操作完成 就执行回调函数(赛跑机制)
    // 例如:文件2.txt 先读取完 
    // 就输出 2.txt 的文件内容 结束
		console.log(results);
	})
	.catch((err) => {
		console.log(err.message);
	});

async/await

::: tip async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作

:::

  • .then 链式调用的优点:解决了回调地狱的问题
  • .then 链式调用的缺点:代码冗余、阅读性差、不易理解

async/await 简化 Promise 异步操作的使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import thenFs from "then-fs";
// 按顺序读取文件 1,2,3 的内容
async function getAllFile() {
	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);
}
getAllFile();

::: warning async/await 的使用注意事项

:::

  • 如果在 function 中使用了 await,则 function 必须被 async 修饰
  • 在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行

EventLoop(事件循环)

JavaScript 主线程从“任务队列”中读取异步任务的回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为 EventLoop(事件循环)。

结合 EventLoop 分析输出的顺序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import thenFs from "then-fs";

console.log('A');
thenFs.readFile("./files/3.txt", "utf8").then(dataStr=>{
    console.log('B');
})
setTimeout(()=>{
    console.log('C');
},0)
 console.log('D');

::: details 查看答案

ADCB

  • A 和 D 属于同步任务。会根据代码的先后顺序依次被执行
  • C 和 B 属于异步任务。它们的回调函数会被加入到任务队列中,等待主线程空闲时再执行

:::

宏任务和微任务

JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:

  • 宏任务(macrotask)
    • 异步 Ajax 请求、
    • setTimeout、setInterval、
    • 文件操作
    • 其它宏任务
  • 微任务(microtask)
    • Promise.then、.catch 和 .finally
    • process.nextTick
    • 其它微任务

::: tip 宏任务和微任务的执行顺序

:::

每一个宏任务执行完之后,都会检查是否存在待执行的微任务,如果有,则执行完所有微任务之后,再继续执行下一个宏任务。

::: tip 宏任务和微任务日常例子

:::

去银行办业务的场景

  1. 小云和小腾去银行办业务。首先,需要取号之后进行排队
    • 宏任务队列
  2. 假设当前银行网点只有一个柜员,小云在办理存款业务时,小腾只能等待
    • 单线程,宏任务按次序执行
  3. 小云办完存款业务后,柜员询问他是否还想办理其它业务?
    • 当前宏任务执行完,检查是否有微任务
  4. 小云告诉柜员:想要买理财产品、再办个信用卡、最后再兑换点马年纪念币?
    • 执行微任务,后续宏任务被推迟
  5. 小云离开柜台后,柜员开始为小腾办理业务
    • 所有微任务执行完毕,开始执行下一个宏任务

::: tip 宏任务和微任务练习例子

:::

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
setTimeout(function () {
	console.log(1);
});
new Promise(function (resolve) {
	console.log(2);
	resolve();
}).then(function () {
	console.log(3);
});
console.log(4);

::: details 查看答案

2431

分析:

  1. 先执行所有的同步任务
    • 第 6 行 ,第 12 行 注:promise 是同步 ,promise.then 回调才是异步
  2. 在执行所有的微任务
    • 第9行
  3. 再执行下一个宏任务
    • 第2行

:::

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JavaScript——ES6模块化与异步编程高级用法
大家都遵守同样的模块化规范写代码,降低了沟通程表,极大方便了各个模块之间的相互调用,利人利己。
岳泽以
2022/10/26
7510
JavaScript——ES6模块化与异步编程高级用法
ES6的异步编程之Generator
异步编程对 JavaScript 语言太重要。JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可。
javascript.shop
2019/09/04
5310
ES6的异步编程之Generator
Node.js异步编程(下)
如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题要怎么解决呢?
Qwe7
2022/04/23
7780
ES6新特性
由于ES6在一些低版本的浏览器上无法运行,需转成ES5之前的版本兼容,以下有几种方案可以自动转换
jinghong
2020/05/09
1K0
ES6新特性
Promise用法详解(一)
注意:上面new出来promise,只代表形式上的一个异步操作。就是说,我们只知道他是一个 异步操作,但做什么具体异步事情目前还不清楚。
全栈程序员站长
2022/07/04
3820
Promise用法详解(一)
nodejs(三)
必须在 package.json 的根节点中添加 "type": "module" 节点
且陶陶
2023/04/12
4520
nodejs(三)
【JS】236-JS 异步编程六种方案(原创)
我们知道Javascript语言的执行环境是"单线程"。也就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。
pingan8787
2019/07/25
9860
【JS】236-JS 异步编程六种方案(原创)
《深入浅出Node.js》:Node异步编程解决方案 之 ES6 Promise
在上一篇讲了异步编程解决方案之一的事件发布-订阅模式,使用事件模式时,执行流程需要被预先设定。即便是分支,也需要预先设定,这是由发布-订阅模式的运行机制决定的。这个方法的灵活性比较受限,那是否有一种先执行异步调用,延迟传递处理的方式呢?在ES6发布之前,解决方案是Promise/Deferred模式,现在则推荐ES6官方提供的Promise。
前端_AWhile
2019/08/29
9280
async关键字
在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
Qwe7
2022/04/23
2750
异步发展流程-手摸手带你实现一个Promise
首先介绍一下高阶函数,即一个函数的参数是函数或者函数返回值为函数,此函数称做高阶函数。
Careteen
2022/02/14
9660
ES6的异步编程之async
异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图解决这个问题。
javascript.shop
2019/09/04
4850
ES6的异步编程之async
ES6 Promise详解之缝合红宝书ES6标准入门
去年暑假的时候就学了Promise,最近在学node的时候又遇到了再复习一遍,写个博客缝合一波阮佬的ES6标准入门与红宝书中的内容,用我自己的白话给大家讲一下。
henu_Newxc03
2021/12/26
6590
Node.js异步编程
1. 同步API,异步API //路径拼接 const public = path.join(_ dirname, 'public') ; //通过返回值拿到 //请求地址解析 const url0bj = url. parse (req. ur1) ; //通过返回值拿到 //读取文件 fs. readFile(' ./demo.txt', 'utf8', (err, result) => { console .1og (result) ; }) ; //通过函数方式拿到 同步API:只有当前
清出于兰
2020/10/29
2K0
Node.js异步编程
day044:JS异步编程有哪些方案?为什么会出现这些方案?
关于 JS 单线程、EventLoop 以及异步 I/O 这些底层的特性,我们之前做过了详细的拆解,不在赘述。在探究了底层机制之后,我们还需要对代码的组织方式有所理解,这是离我们最日常开发最接近的部分,异步代码的组织方式直接决定了开发和维护的效率,其重要性也不可小觑。尽管底层机制没变,但异步代码的组织方式却随着 ES 标准的发展,一步步发生了巨大的变革。接着让我们来一探究竟吧!
用户3806669
2021/03/10
6770
从零开始写一个符合Promises/A+规范的promise
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。本篇不注重讲解promise的用法,关于用法,可以看阮一峰老师的ECMAScript 6系列里面的Promise部分:
桃翁
2019/10/23
1.1K0
从零开始写一个符合Promises/A+规范的promise
记两道关于事件循环的题
这里的关键其实是搞清楚 await async2() 做了什么事情。我以为在 async1 内部,async2 被调用之后,就会继续往后执行,因此是先打印 async1 end ,再回到主栈打印 start。然而 async2 里面包含了一个异步操作,在异步操作得到结果之前,其实是会跳出当前 async1 函数的执行栈,优先去执行同步任务的,所以这里其实会先执行 start,再去执行 async1 end。具体地说:
Chor
2020/05/18
4100
Promise解决回调嵌套问题及终极解决方案async 和 await
目的: promise是书写异步代码的另一种方式, 解决回调函数嵌套的问题 1.如何创建一个 promise 对象
青梅煮码
2023/03/02
2.4K0
js异步编程的三种模式
很容易可以看出,上述代码会依次输出1,2。因为代码是从上到下,依次执行,执行完f1(),才会执行f2()。但是如果f1()中的代码执行的是读取文件或者ajax操作呢,文件的读取都需要一定时间,难道我们需要完全等到文件完全读完再进行写操作么?为了解决这个问题,接下来我们来探究一下js中 同步和异步 的概念。
hellocoder2029
2022/09/28
8660
Node理论笔记:异步编程
在JavaScript中,函数是一等公民,使用非常自由,无论是调用它,或者作为参数,或者作为返回值均可。
Ashen
2020/06/01
1.1K0
JavaScript异步编程
平时开发经常会用到js异步编程,由于前端展示页面都是基于网络机顶盒(IPTV的一般性能不太好,OTT较好),目前公司主要采取的异步编程的方式有setTimeout、setInterval、requestAnimationFrame、ajax,为什么会用到异步呢,就拿业务来说,若前端全部采取同步的方式,那加载图片、生成dom、网络数据请求都会大大增加页面渲染时长。
Jack Chen
2018/09/14
9290
JavaScript异步编程
相关推荐
JavaScript——ES6模块化与异步编程高级用法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验