浏览器渲染过程
问:在浏览器中,从输入UR到页面展示,这中间发生了什么?
如下图,一个浏览器有三个进程,浏览器进程、网络进程以及渲染进程。
- 网络进程中,发起url请求后有可能会进行一个重定向,然后读取响应头信息(这个信息会告诉浏览器我是HTML还是其他的谁),读取响应体数据(就是网页源代码)。
- 渲染过程
a. 处理HTML构建DOM树
b. 处理CSS构建CSSOM树
c. 将DOM和CSSOM合并成一个渲染树
d. 根据渲染树布局,计算每个节点几何信息
e. 将几何信息绘制在屏幕上
JavaScript实用技巧
var 和 let/const
//我们想让这段代码隔0.1S打印0到9.但是结果打印了10个10
for (var i = 0;i < 10;i++) {
setTimeout(function(){
console.log(i);},100);
}
//这是因为var会提升作用域,提升到全局。
//setTimeout延迟100ms,但是for循环瞬间就执行了10次,所以每次当100ms到的时候,i已经等于10了
var i = 0;
for (i = 0;i < 10;i++) {
setTimeout(function(){
console.log(i);},100);
}
//换成ES6的let就可以了
for (let i = 0;i < 10;i++) {
setTimeout(function(){
console.log(i);},100);
}
实际上当使用 let
的时候,编译器会将 let
换成 var
,就是将 var
的作用域变成块作用域.
//编译之后大概是这样
function print(i){
setTimeout(function(){
console.log(i);},100);
}
for (var i = 0;i < 10;i++) {
print(i);
}
箭头函数
- 例子1 ```javascript for (let i = 0;i < 10;i++) { setTimeout(function(){ console.log(i);},1000); }
//使用箭头函数 for (let i = 0;i < 10;i++) { setTimeout(() => { console.log(i);},1000); }
2. 例子2
```javascript
function abc(){
console.log('abc');
}
//使用箭头函数
const abc = () => {
console.log('abc');
}
- 例子3 ```javascript function sum(a,b) { return a+b; }
//使用箭头函数 const sum = (a,b) => { return a+b; }
//简化 const sum = (a,b) => a+b;
<a name="u7tZy"></a>
### 回调函数 & Promise
比如给一个元素添加一个监听事件就是是一个回调函数。
```javascript
//箭头函数就是回调函数
document.addEventListener('click',()=>{
});
为什么会出现回调函数?
- 理解同步和异步:
同步要等待其他事做完才会接着做下面的事,是按顺序执行(烧完水才能吃东西)
异步在做一件事的同时还可以做其他事(一边烧水,一边吃东西)
- 异步很方便,JS中通过使用回调函数来进行异步操作
例子:进入优课达网站要进行: 登录=>获取用户信息=>获取我的课程=>初始化
function login(){
//模拟一下登录需要1s
setTimeout(()=>{
console.log('登录成功');
},1000);
}
function getUserInfo(){
setTimeout(()=>{
console.log('获取用户信息成功');
},2000);
}
function getMyCourse(){
setTimeout(()=>{
console.log('获取课程信息成功');
},3000);
}
function init() {
login();
getUserInfo();
getMyCourse();
console.log('初始化成功');
}
init();
------------------
输出结果:
初始化成功
登录成功
获取用户信息成功
获取课程信息成功
这里就出现了问题,虽然是异步执行的(登录需要1s,所以就先去执行初始化了),但是还没有登录,也没有获取到用户信息如何初始化呢?这时就需要回调函数了。
//模拟回调函数callback 登录成功以后你再来调用我
function login(callback){
//模拟一下登录需要1s
setTimeout(()=>{
console.log('登录成功');
callback();
},1000);
}
//获取到信息以后你再来调用我
function getUserInfo(callback){
setTimeout(()=>{
console.log('获取用户信息成功');
callback();
},2000);
}
//获取到我的课程以后再来调用我
function getMyCourse(callback){
setTimeout(()=>{
console.log('获取课程信息成功');
callback();
},3000);
}
function init() {
/**
login的回调函数调用getUserInfo,
getUserInfo的回调函数调用getMyCourse,
getMyCourse的回调里面初始化成功
*/
login(()=>{
getUserInfo(()=>{
getMyCourse(()=>{
console.log('初始化成功');
});
});
});
}
init();
----------------------
输出结果:
登录成功
获取用户信息成功
获取课程信息成功
初始化成功
上面的写法结果是正确的,完全可。但是实际情况是每一个函数里面都有复杂的逻辑,而且还会有更多的请求函数,比如还要获取当前的打卡进度,获取课程进度等,那就需要一直回调,就变成了 回调地狱 。
ES6出现Promise 解决回调地狱
Promise
的出现就是为了去掉回调。
//promise会自动传一个resolve进来,函数执行完以后调用一下resolve就行了
function login(){
return new Promise((resolve,reject) => {
setTimeout(()=>{
console.log('登录成功');
resolve();
},1000);
});
}
function getUserInfo(){
return new Promise((resolve,reject) => {
setTimeout(()=>{
console.log('获取用户信息成功');
resolve();
},2000);
});
}
function getMyCourse(){
return new Promise((resolve,reject) => {
setTimeout(()=>{
console.log('获取课程信息成功');
resolve();
},3000);
});
}
function init() {
//先登录然后执行一个函数,这个函数里面执行getUserInfo()
//然后再执行个函数里面执行getMyCourse
login()
.then(()=>{
return getUserInfo();
})
.then(() => {
return getMyCourse();
})
.then(() =>{
console.log('初始化成功');
});
}
//简化init()
function init() {
login()
.then(getUserInfo)//这里注意传进去的不是函数而是函数执行的结果
.then(getMyCourse)
.then(() =>{
console.log('初始化成功');
});
}
init();
----------------------
输出结果:
登录成功
获取用户信息成功
获取课程信息成功
初始化成功
Promise
的用法和 fetch
很像。其实 fetch
本身就是一个 Promise
,只有 promise
才有 .then
这个方法。
ES7 async & await
ES7用 async
和 await
又做了简化, await
后面接的一定是 promise
的东西。
//异步
async function init() {
//等待
await login();
await getUserInfo();
await getMyCourse();
console.log('初始化成功');
}