模块化
模块导出
let n1 = 11;
let n2 = 22;
export let n3 = 33; //导出
function show(){};
export default{ //默认导出
n1,
n2,
show
};
import m1,{n3} from '@/js/child.js'
console.log(m1,n3);
{n1: 11, n2: 22, show: ƒ}33
默认导出的注意事项:
每一个JS文件,默认导出export default只能使用一次。默认导出和按需导出不是同一个导出。
按需导出的注意事项:
- 每个模块可以多次按需导出
- 按需导入的成员名称必须和按需导出的成员名称一致
- 按需导入时,可以使用as关键字进行重命名
异步编程
- 回调地狱
在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱。
var sayhello = function (name, callback) {
setTimeout(function () {
console.log(name);
callback();
}, 1000);
}
sayhello("first", function () {
sayhello("second", function () {
sayhello("third", function () {
console.log("end");
});
});
});
//输出: first second third end
- 使用promise解决回调地狱
采用链式的 then,可以指定一组按照次序调用的回调函数。这时,前一个 then 里的一个回调函数,返回的可能还是一个 Promise对象(即有异步操作),这时后一个回调函数,就会等待该 Promise对象的状态发生变化,才会被调用。由此实现异步操作按照次序执行。链式编程的回调形式,使用then将回调函数放在主函数的外面,提高了函数的可读性。
var sayhello = function (name) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(name);
resolve(); //在异步操作执行完后执行 resolve() 函数
}, 1000);
});
}
sayhello("first").then(function () {
return sayhello("second"); //仍然返回一个 Promise 对象
}).then(function () {
return sayhello("third");
}).then(function () {
console.log('end');
}).catch(function (err) {
console.log(err);
})
//输出:first second third end
上面代码中,第一个 then 方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就继续执行第二个 then 里的回调函数。Catch放在最后,中途发生错误,回调链直接终止;每个then单独安排catch,只会负责抓取自己负责的then回调,不影响后续的功能
promise
promise有三种状态:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功完成。
- 已拒绝(rejected):意味着操作失败。
初始状态为pending,改为fulfilled,rejected状态才会调用相应的回调函数,每个状态只会改变一次。
promise注意:
- promise是一个构造函数,new Promise()产生的实例对象,代表一个异步操作。
- p.then(成功的回调函数,失败的回调函数)、
- 调用then方法时,成功的回调函数是必选的,失败的回调函数是选用。
const p = new Promise((resolve,reject)=>{
resolve("成功");
});
p.then(s=>{
console.log(s)
console.log("dcscsd");
},f=>{
console.log(f)
})
结果:成功
dcscsd
==============================================================
const p = new Promise((resolve,reject)=>{
reject("失败");
});
p.then(s=>{
console.log(s)
console.log("dcscsd");
},f=>{
console.log(f)
})
结果:失败
Promise.all()和Promise.race()
const p1 = new Promise((resolve,reject)=>{
setTimeout(resolve(1),2000);
});
const p2 = new Promise((resolve,reject)=>{
setTimeout(resolve(2),3000);
});
const p3 = new Promise((resolve,reject)=>{
setTimeout(resolve(3),5000);
});
const arry =[p1,p2,p3];
Promise.all(arry).then(([p1,p2,p3])=>{
console.log(p1,p2,p3)
})
Promise.race(arry).then((r)=>{
console.log(r)
})
结果:
1 2 3
1
- Promise.all()所有promise状态都改变时才返回。
- Promise.race()有一个状态改变就返回
async/await
ES8的语法,简化Promise异步操作。在async/await出现前,只能用链式.then()方式处理Promise异步操作读取的本来是一个promise实例对象,内容需要用.then获取,但是用了async和await之后就直接出现了结果。方法内用到了await,方法外就需要用async修饰;在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行。
async function fun(){
const p = new Promise((resolve,reject)=>{
console.log("p1 11111")
setTimeout(resolve(1),100000);
console.log("p1 22222")
});
const test2 = await 2;
console.log("p1 33333")
const test = await p;
console.log("p1 44444")
console.log(test)
console.log("p1 555555")
}
console.log(1)
fun()
console.log(2)
结果:
1
p1 11111
p1 22222
2
p1 33333
p1 44444
1
p1 555555
await是语法糖简化了then方法的使用,await前面的代码会同步,await后面的代码异步执行。
function fun() {
const p = new Promise((resolve, reject) => {
console.log("p1 11111")
setTimeout(resolve(1), 100000);
console.log("p1 22222")
});
const test2 = new Promise((resolve, reject) => {
resolve(2)
});
test2.then(s => {
console.log("p1 33333")
return p;
}).then(s => {
console.log("p1 44444")
console.log(s)
console.log("p1 555555")
})
}
console.log(1)
fun()
console.log(2)
await等价于,创建一个promise对象,将后面的操作放入then回调中。
EventLoop
同步任务和异步任务
js是单线程执行的编程语言,为防止某个耗时的任务导致程序假死的问题,js把待执行任务分两类:
- 同步任务/非耗时任务
指的是在主线程上排队执行的任务,只有前一个执行完毕才能执行后一个任务
- 异步任务/耗时任务
由js委托给宿主环境进行执行,执行完后会通知js主线程执行异步任务的回调函数
宏任务和微任务
异步任务按照是否需要连贯执行,分为宏任务和微任务。
如何理解连贯执行?
比如去银行办理业务需要排队办理,当办理完查余额、存钱等业务后,业务员会问需要办理财业务吗?如
果你需要,业务员会继续为你办理财业务,而不需要重新排队。这里的排队办业务是宏任务,而办理理财 业务具有连贯性,是微任务。
宏任务和微任务的执行原理
事件循环机制的原理
JS是单线程的语言,为了避免程序的假死,采用事件循环机制。JS的任务分为同步任务和异步任务,同步任务由JS主线程执行,异步任务由宿主环境(浏览器或者node)执行。优先完执行同步任务,若遇见宏任务和微任务,分别将其交给宿主环境处理,异步任务完成后,注册回调函数交给执行队列。同步代码执行完或者一次事件循环执行完,查看回调执行队列如果存在宏任务回调函数,就执行该宏任务的回调函数,执行完该宏任务的回调函数后,查看回调执行任务队列中微任务的回调函数将其逐一执行,此为一次事件循环,进行下一次事件循环。