前言
整顿了一下 javascript 的基础知识,在此给大家做下分享,喜爱的大佬们能够给个赞。
js 是一门单线程语言。 js 引擎有一个主线程(main thread)用来解释和执行 js 程序,实际上还存在其余的线程。例如:解决 ajax 申请的线程、解决 DOM 事件的线程、定时器线程、读写文件的线程(例如在 node.js 中)等等。这些线程可能存在于 js 引擎之内,也可能存在于 js 引擎之外,在此咱们不做辨别。无妨叫它们工作线程。
JS 执行上下文
当代吗运行时,会产生对应的运行环境,在这个环境中,所有的变量都会备实现提出来(变量晋升),有的间接赋值,有的默认赋值,有点默认值 undefined ,代码从上而下开始执行,就叫做执行上下文。
1、变量晋升
foo // undefinedvar foo = function () { console.log('foo1')}foo() // foo1, foo赋值var foo = function () { console.log('foo2')}foo() // foo2, foo 赋值
2、函数晋升
foo() // foo2function () { console.log('foo1')}foo() // foo2function foo () { console.log('foo2')}foo() // foo2
3、申明优先级,函数 > 变量
foo() // foo2var 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,还有将来炽热的鸿蒙,当各种元素组合在一起,让咱们一起脑洞大开独特打造业余、好玩、有价值的开发者社区,帮忙开发者实现自我价值!