共计 3509 个字符,预计需要花费 9 分钟才能阅读完成。
前言
整顿了一下 javascript 的基础知识,在此给大家做下分享,喜爱的大佬们能够给个赞。
js 是一门单线程语言。js 引擎有一个主线程(main thread)用来解释和执行 js 程序,实际上还存在其余的线程。例如:解决 ajax 申请的线程、解决 DOM 事件的线程、定时器线程、读写文件的线程 (例如在 node.js 中) 等等。这些线程可能存在于 js 引擎之内,也可能存在于 js 引擎之外,在此咱们不做辨别。无妨叫它们工作线程。
JS 执行上下文
当代吗运行时,会产生对应的运行环境,在这个环境中,所有的变量都会备实现提出来(变量晋升),有的间接赋值,有的默认赋值,有点默认值 undefined,代码从上而下开始执行,就叫做执行上下文。
1、变量晋升
foo // undefined
var foo = function () {console.log('foo1')
}
foo() // foo1, foo 赋值
var foo = function () {console.log('foo2')
}
foo() // foo2, foo 赋值
2、函数晋升
foo() // foo2
function () {console.log('foo1')
}
foo() // foo2
function foo () {console.log('foo2')
}
foo() // foo2
3、申明优先级,函数 > 变量
foo() // foo2
var foo = function () {console.log('foo1')
}
foo() // foo1, foo 从新赋值
function foo () {console.log('foo2')
}
foo() // foo1
运行环境
在 javascript 的世界中,运行环境有三种,别离是:
1、全局环境:代码首先进入环境
2、函数环境:函数被调用时执行的环境
3、eval 函数:(不罕用)
执行上下文特点
1、单线程,在主线程上进行
2、同步执行,从上往下按程序执行
3、全局上下文只有一个,浏览器敞开时会被弹出栈
4、函数执行上下文没有数目限度
5、函数每被调用一次,都会产生一个新的执行上下文环境
执行上下文栈
执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会长生一个执行上下文环境。当函数调用实现时,这个上下文环境以及其中的数据都会被打消,再从新回到全局上下文环境,处于活动状态的执行上下文环境只有一个。
其实这是一个压栈出栈的过程————执行上下文栈
var // 1. 进入全局上下文环境
a = 10,
fn,
bar = function (x) {
var b = 20
fn(x + b) // 3. 进入 fn 上下文环境
}
fn = function (y) {
var c = 20
console.log(y + c)
}
bar(5) // 2. 进入 bar 上下文环境
执行上下文的生命周期
1、创立阶段
- 生成变量对象
- 建设作用域链
- 确定 this 指向
2、执行阶段
- 变量赋值
- 函数援用
- 执行其余代码
3、销毁阶段
- 执行出栈结束,期待回收被销毁
javascript 事件循环
- 同步和异步工作别离进入不同的执行“场合”,同步的进入主线程,异步的进入 Event Table 并注册函数
- 当指定事件实现时,Event Table 会将这个函数移入 Event Queue
- 主线程内的工作执行结束为空,会去 Event Queue 读取对应的函数,进入主线程执行
- 上述过程会一直反复,也就是常说的 Event Loop(事件循环)
同步工作和异步工作,咱们对工作有更精密的定义:
macro-task(宏工作)
能够了解是每次执行栈执行的代码就是一个宏工作(包含每次从事件队列中获取一个事件回调并放到执行栈中执行)
浏览器为了可能使得 JS 外部 (macro)task 与 DOM 工作可能有序执行,会在一个 (macro)task 执行完结后,在下一个 (macro)task 执行开始前,对页面进行从新渲染
(macro)task 次要蕴含:script (整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)
micro-task(微工作)
能够了解是在以后 task 执行完结后立刻执行的工作。也就是说,在以后的 task 工作后,下一个 task 之前,在渲染之前。所以他的响应熟读比 setTimeout 会更快,因为无需等渲染。也就是说,在摸一个 macrotask 执行完后,就会将在它执行期间产生的所有 mocrotask 都执行结束(在渲染前)。
macrotask 次要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)
举个例子
咱们来剖析一段比较复杂的代码,看看你是否真的把握了 js 的执行机制
consoloe.log('1')
setTimeout(function () {console.log('2')
process.nextTick(function () {console.log('3')
})
new Promise(function (resolve) {console.log('4')
resolve()}).then(function () {console.log('5')
})
})
process.nextTick(function () {console.log('6')
})
new Promise(function (resolve) {console.log('7')
resolve
}).then(function () {console.log('8')
})
setTimeOut(function () {console.log('9')
process.nextTick(function () {console.log('10')
})
new Promise(function (resolve) {console.log('11')
resolve()}).then(function () {console.log('12')
})
})
// 1, 7, 8, 2, 4, 5, 6, 3, 9, 11, 12, 10
又一个例子
async function async1 () {console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2 () {console.log('async2')
}
console.log('script start')
setTimeout(function () {console.log('setTimeout')
}, 0)
async1()
new Promise(function (resolve) {console.log('promise1')
resolve()}).then(function () {console.log('promise2')
})
console.log('sacript end')
// script start
// async1 start
// async2
// promise1
// script end
// async end
// promise2
// setTimeout
解决异步的办法
1、回调函数
ajax('x1', () => {
// callback 函数体
ajax('x2', () => {
// callback 函数体
ajax('x3', () => {// callback 函数体})
})
})
- 长处:解决了同步的问题
- 毛病:回调天堂,不能用 try catch 捕获谬误,不能 return
2、Promise 为了解决 callback 的问题而产生
Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新的 Promise,如果咱们在 then 中 return,return 的后果会被 Promise.reolve() 包装
- 长处:解决了回调天堂
- 毛病:无奈勾销 Promise,谬误须要通过回调函数来捕捉
3、Async/await
- 长处是:代码清晰,不必 Promise 写一大堆 then 链,解决了回调天堂问题
- 毛病:await 将异步代码革新成同步代码,如果多个异步操作没有依赖性而应用 await 会导致性能上的升高
总结
- javascript 是一门单线程语言
- Event Loop 是 javascript 的执行机制
原文链接:https://www.sdk.cn/details/eqZPyk7Agy4eb5QxXw
SDK 社区 是一个中立的社区,这里有多样的前端常识,有丰盛的 api,有爱学习的人工智能开发者,有有趣风趣的开发者带你学 python,还有将来炽热的鸿蒙,当各种元素组合在一起,让咱们一起脑洞大开独特打造业余、好玩、有价值的开发者社区,帮忙开发者实现自我价值!