node.js 遵循了 CommonJS 的模块化规范。其中:
模块化开发的好处有很多,其中:
在 ES6 模块化规范诞生之前,JavaScript 社区已经尝试并提出了 AMD 、 CMD 、 CommonJS 等模块化规范。
但是,这些由社区提出的模块化标准,还是存在一定的差异性与局限性、并不是浏览器与服务器通用的模块化标准
模块化太多的模块化规范给开发者增加了学习的难度与开发的成本。因此,官方的 ES6 模块化规范诞生了!
node.js 中默认仅支持 CommonJS 模块化规范,若想基于 node.js 体验与学习 ES6 的模块化语法,需要按照如下两个步骤进行配置:
三种方式:1.导入导出缺省的对象.2.按需导入导出2.仅导入导出逻辑
a.js文件:
// // 创建文件夹: 注意别有特殊符号和汉字 // // 初始化: npm init -y // // 导入方法1 - 前缀后缀不能省略; // // default导出的数据,不能解构; // import obj from './02-b.js'; // console.log(obj); // obj.c(); // 导入方法2 - 前缀后缀不能省略; // 按需导出的数据,必须解构导入 import { d, e, f as fn } from './02-b.js'; console.log(d, e); fn(); // // 导入方法3 - 只导入,不接收; // import './02-b.js'
b.js文件:
// // 导出方法1 // // default导出,不能解构; // export default { // a: 1, // b: 2, // c: () => console.log('我是函数c') // } // 导出方法2 - 按需导出 // 必须以解构的方式接收 export let d = 3; export const e = 4; export function f() { console.log('我是函数f'); } // // 第三种导出,一般使用的是逻辑,不是导出的具体值 // console.log('忽有故人人上过,回首山河已是秋。他朝若是同淋雪,此生也算共白头。');
异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图解决这个问题。早期使用回调函数处理异步编码,但存在回调地狱的问题。ES6中,新增了Promise 对象,从此异步编程摆脱了回调函数的束缚。
let p = new Promise((resolve, reject) => { // ... some code if (/* 异步操作成功 */) { resolve(value); } else { reject(error); } });
注意点:
p.then( result => { /* 获取成功的结果 */ } ); // 或者 p.then( result => { /* 获取成功的结果 */ }, err => { /* 获取失败的结果 */ } ); // 或者 p.then( result => { /* 获取成功的结果 */ } ).catch( err => { /* 获取失败的结果 */ } );
注意点:
new Promise 和 new 其他对象一样,是同步任务。
获取结果时(调用 resolve 触发 then方法时)是异步的。
代码略;
// 封装 function myReadFile(filename) { return new Promise((resolve, reject) => { fs.readFile(filename, 'utf-8', (err, data) => { err ? reject(err) : resolve(data.length); }) }); } // 调用 myReadFile('./files/a.txt') .then(a => { console.log(a); return myReadFile('./files/b.txt'); }) .then(b => { console.log(b); return myReadFile('./files/c.txt'); }) .then(c => { console.log(c) })
// npm i then-fs const fs = require('then-fs'); fs.readFile('./files/a.txt', 'utf-8') .then(res1 => { console.log(res1); return fs.readFile('./files/b.txt', 'utf-8') }) .then(res2 => { console.log(res2); return fs.readFile('./files/b.txt', 'utf-8') }) .then(res3 => { console.log(res3) })
注意:未来很多模块支持Promise对象开发,就是返回的是一个Promise对象; 如 axios
async 和 await 是 ES2017 中提出来的,async 和 await 两个关键字的出现,简化的 Promise 的使用。
async关键字使用比较简单,所以 async 的使用注意以下三点即可 :
await关键字比较繁琐,注意点比较多。首先,await 只能出现在 async 函数内,await 让 JS 引擎等待直到promise完成并返回结果,语法:
let value = await promise对象; // 等待promise对象的结果,然后将结果赋值给 value
由于await需要等待promise执行完毕,所以 await会 暂停函数的执行,但不会影响其他同步任务。
所以,await总结如下四点:
// async 和 await 解决回调地狱也要用到 then-fs ,因为他直接返回 Promise 对象; // 导入 then-fs import thenFs from 'then-fs'; // await 一定要出现在异步函数中 async function fn() { let str1 = await thenFs.readFile('./txt/a.txt', 'utf8'); console.log(str1); let str2 = await thenFs.readFile('./txt/b.txt', 'utf8'); console.log(str2); let str3 = await thenFs.readFile('./txt/c.txt', 'utf8'); console.log(str3); } // 调用函数 fn();
在ES3 以及以前的版本中,JavaScript本身没有发起异步请求的能力,也就没有微任务的存在。在ES5之后,JavaScript引入了Promise,这样,不需要浏览器,JavaScript引擎自身也能够发起异步任务了。
Tick会触发浏览器渲染,Promise不会触发,所以更加轻量级,多使用;
(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务
微任务(microtask)是宏任务中的一个部分,它的执行时机是在同步代码执行之后,下一个宏任务执行之前。总结起来,微任务有:
JS优先执行同步任务,然后执行微任务,最后执行宏任务。
总结:Promise中的then()比大部分异步代码,优先执行!