javascript 是一门单线程的语言,在同一个时间只能做完成一件任务,如果有多个任务,就必须排队,前面一个任务完成,再去执行后面的任务。作为浏览器端的脚本语言,javascript 的主要功能是用来和用户交互以及操作 dom。假设 javascript 不是单线程语言,在一个线程里我们给某个 dom 节点增加内容的时候,另一个线程同时正在删除这个 dom 节点的内容,则会造成混乱。
由于 js 单线程的设计,假设 js 程序的执行都是同步。如果执行一些耗时较长的程序,例如 ajax 请求,在请求开始至请求响应的这段时间内,当前的工作线程一直是空闲状态, ajax 请求后面的 js 代码只能等待请求结束后执行,因此会导致 js 阻塞的问题。
javascript 单线程指的是浏览器中负责解释和执行 javascript 代码的只有一个线程,即为 js 引擎线程,但是浏览器的渲染进程是提供多个线程的,如下:
为解决上述类似上述 js 阻塞的问题,js 引入了同步和异步的概念。
“同步”就是后一个任务等待前一个任务结束后再去执行。
“异步”与同步不同,每一个异步任务都有一个或多个回调函数。webapi 会在其相应的时机里将回调函数添加进入消息队列中,不直接执行,然后再去执行后面的任务。直至当前同步任务执行完毕后,再把消息队列中的消息添加进入执行栈进行执行。
异步任务在浏览器中一般是以下:
“栈”是一种数据结构,是一种线性表。特点为 LIFO,即先进后出 (last in, first out)。
利用数组的 push 和 shift 可以实现压栈和出栈的操作。
在代码运行的过程中,函数的调用会形成一个由若干帧组成的栈。
function foo(b) {
let a=10;
return a + b + 11;
}
function bar(x) {
let y=3;
return foo(x * y);
}
console.log(bar(7))
上面代码最终会在控制台打印42,下面梳理一下它的执行顺序。
对象被分配在堆中,堆是一个用来表示一大块(通常是非结构化的)内存区域的计算机术语。
首先,stack 是有结构的,每个区块按照一定次序存放,可以明确知道每个区块的大小;heap 是没有结构的,数据可以任意存放。因此,
stack 的寻址速度要快于 heap。
其次,每个线程分配一个 stack,每个进程分配一个 heap,也就是说,stack 是线程独占的,heap 是线程共用的。
此外,stack 创建的时候,大小是确定的,数据从超过这个大小,就发生 stack overflow 错误,而 heap 的大小是不确定的,
需要的话可以不断增加。
public void Method1()
{
int i=4;
int y=2;
class1 cls1=new class1();
}
上面代码这三个变量和一个对象实例在内存中的存放方式如下。
从上图可以看到,i、y和cls1都存放在stack,因为它们占用内存空间都是确定的,而且本身也属于局部变量。但是,cls1指向的对象实例存放在heap,因为它的大小不确定。作为一条规则可以记住,所有的对象都存放在heap。
接下来的问题是,当Method1方法运行结束,会发生什么事?
回答是整个stack被清空,i、y和cls1这三个变量消失,因为它们是局部变量,区块一旦运行结束,就没必要再存在了。而heap之中的那个对象实例继续存在,直到系统的垃圾清理机制(garbage collector)将这块内存回收。因此,一般来说,内存泄漏都发生在heap,即某些内存空间不再被使用了,却因为种种原因,没有被系统回收。
队列是一种数据结构,也是一种特殊的线性表。特点为 FIFO,即先进先出(first in, first out)
利用数组的 push 和 pop 可实现入队和出队的操作。
事件循环和事件队列的维护是由事件触发线程控制的。
事件触发线程线程同样是由浏览器渲染引擎提供的,它会维护一个事件队列。
js 引擎遇到上文所列的异步任务后,会交个相应的线程去维护异步任务,等待某个时机,然后由事件触发线程将异步任务对应的回调函数加入到事件队列中,事件队列中的函数等待被执行。
js 引擎在执行过程中,遇到同步任务,会将任务直接压入执行栈中执行,当执行栈为空(即 js 引擎线程空闲), 事件触发线程 会从事件队列中取出一个任务(即异步任务的回调函数)放入执行在栈中执行。
执行完了之后,执行栈再次为空,事件触发线程会重复上一步的操作,再从事件队列中取出一个消息,这种机制就被称为 事件循环 (Event Loop)机制。
为了更好地理解Event Loop,请看下图(转引自Philip Roberts的演讲《Help, I'm stuck in an event-loop》)。
例子代码:
console.log('script start')
setTimeout(()=> {
console.log('timer 1 over')
}, 1000)
setTimeout(()=> {
console.log('timer 2 over')
}, 0)
console.log('script end')
// script start
// script end
// timer 2 over
// timer 1 over
模拟 js 引擎对其执行过程:
此时,执行栈为空,js 引擎线程空闲。便从事件队列中读取任务,此时队列如下:
注意点:
上面,timer 2 的延时为 0ms,HTML5标准规定 setTimeout 第二个参数不得小于4(不同浏览器最小值会不一样),不足会自动增加,所以 "timer 2 over" 还是会在 "script end" 之后。
就算延时为0ms,只是 time 2 的回调函数会立即加入事件队列而已,回调的执行还是得等到执行栈为空时执行。
在 ES6 新增 Promise 处理异步后,js 执行引擎的处理过程又发生了新的变化。
看代码:
console.log('script start')
setTimeout(function() {
console.log('timer over')
}, 0)
Promise.resolve().then(function() {
console.log('promise1')
}).then(function() {
console.log('promise2')
})
console.log('script end')
// script start
// script end
// promise1
// promise2
// timer over
这里又新增了两个新的概念, macrotask (宏任务)和 microtask (微任务)。
所有的任务都划分到宏任务和微任务下:
js 引擎首先执行主代码块。
执行栈每次执行的代码就是一个宏任务,包括任务队列(宏任务队列)中的。执行栈中的任务执行完毕后,js 引擎会从宏任务队列中去添加任务到执行栈中,即同样是事件循环的机制。
当在执行宏任务遇到微任务 Promise.then 时,会创建一个微任务,并加入到微任务队列中的队尾。
微任务是在宏任务执行的时候创建的,而在下一个宏任务执行之前,浏览器会对页面重新渲染(task >> render >> task(任务队列中读取))。 同时,在上一个宏任务执行完成后,页面渲染之前,会执行当前微任务队列中的所有微任务。
所以上述代码的执行过程就可以解释了。
js 引擎执行 promise.then 时,promise1、promise2 被认为是两个微任务按照代码的先后顺序被加入到微任务队列中,script end执行后,栈空。
此时当前宏任务(script 主代码块)执行完毕,并不从当前宏任务队列中读取任务。而是立马清空当前宏任务所产生的微任务队列。将两个微任务依次放入执行栈中执行。执行完毕,打印 promise1、promise2。栈空。 此时,第一轮事件循环结束。
紧接着,再去读取宏任务队列中的任务,time over 被打印。栈空。
因此,宏任务和微任务的执行机制如下:
因为,async 和 await 本质上还是基于 Promise 的封装,而 Promise 是属于微任务的一种。所以使用 await 关键字与 Promise.then 效果类似:
setTimeout(_=> console.log(4))
async function main() {
console.log(1)
await Promise.resolve()
console.log(3)
}
main()
console.log(2)
// 1
// 2
// 3
// 4
async 函数在 await 之前的代码都是同步执行的, 可以理解为 await 之前的代码都属于 new Promise 时传入的代码,await 之后的所有代码都是 Promise.then 中的回调,即在微任务队列中。
参考:
原文作者:大芒果哇
原文地址:https://www.cnblogs.com/shenggao/p/13799566.html
者:樱桃小丸子儿
来源:https://www.jianshu.com/p/2f7eb1ad7174
1、Html5与html4相比,各有何优缺点? 怎样处理html5新标签的兼容性问题?
html5余html4的异同请看以下的链接
html5与html4的异同
兼容性问题
IE8/IE7/IE6支持通过document.createElement方法产生的标签,可以利用这一特性让这些浏览器支持HTML5新标签,浏览器支持新标签后,还需要添加标签默认的样式。当然也可以直接使用成熟的框架、比如html5shim。
<!--[if lt IE 9]> <script> src="http://html5shim.googlecode.com/svn/trunk/html5.js"</script> <![endif]-->
1、JS如何使页面跳转?怎么引入一个外部JS文件?
①直接在head标签内写入js代码,如下
<Script Language="JavaScript">js 语句</Script>
②引入写好的js文件,使用语句
<script language="JavaScript" src="test.js"></script>
也是直接放入到head标签里头,也有的是放在</body>前面。
2、输入框的验证用什么事件?
change(fn)
3、undefined与null有何异同?
null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
undefined:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
null:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
它们都表示空,转换为boolean后都为false,但是null代表一个对象变量已经被初始化,但未装入对象;undefined表示未初始化变量
4、===与==有何异同?
相同点:都是判定两个值是否相等
不同点:==不会判断类型,而===会判断类型
5、如何判断一个变量的值是否为数字?以及有哪些手段判断变量值的数据类型?
全局函数isNaN可以判断一个变量的值是否为数字。
可以使用运算符type、instanceof判断变量值的数据类型。
6、什么是Bom什么是Dom?你如何理解Dom?
链接标记target与Dom,Bom
7、Array的join、push、splice、slice各有何用途,splice与slice有何异同?
join:使用指定间隔符连接所有元素为字符串
push:在尾部添加元素并维护array实例的length
splice与slice都是截取一部分元素。不同的在于:slice返回截取后的新实例,splice在原array实例上操作,更详细的请见下文链接。
JS中数组对象详解
8、如何阻止表单提交?
在onsubmit事件中返回false
9、如何动态操作表格?
可以像普通dom一样操作,但是因为表格的dom比较复杂,所以我通常是使用table的insertRow、deleteRow及tr对象的insetCell、deleteCell操作。
10、String.match与RegExp.exec有何区别?
match只会返回没有分组的全部匹配结果或者有分组的第一次匹配结果;
而exec可以利用循环返回全部匹配结果。
11、为验证手机号写一个正则。
function checkSubmitMobil() { if ($("#phoneNum").val()=="") { alert("手机号码不能为空!"); //$("#moileMsg").html("<font color='red'>手机号码不能为空!</font>"); $("#mobile").focus(); return false; } if (!$("#phoneNum").val().match(/^(?:13\d|15\d|18\d)\d{5}(\d{3}|\*{3})$/)) { alert("手机号码格式不正确!"); //$("#moileMsg").html("<font color='red'>手机号码格式不正确!请重新输入!</font>"); $("#phoneNum").focus(); return false; } return true; }
12、正则的i标记与g标记各有何用途?
i:不区分大小写;
g:全局匹配。
13、为String添加trim()方法。
String.prototype.trim=function() { return this.replace(/^ +| +$/g,""); }
14、简述COOKIE。在JS中如何操作Cookie?
简述cookie,在JS中如何操作cookie
15、谈谈javascript数组排序方法sort()的使用,重点介绍sort()参数的使用及其内部机制。
JS数组排序方法sort()的使用
16、谈谈innerHTML outerHTML innerText之间的区别。
①innerHTML是w3c的html dom定义的方法,而后两者是IE独有的方法;
②innerHTML代表一个元素节点内由所有子节点,不包括当前节点组成的html代码;
③outerHTML代表一个元素节点内由所有子节点和当前节点组成的html代码;
④innerText代表一个元素节点内由所有子文本节点内容组成的文本;
17、在JavaScript中定时调用函数 foo() 如何写?
setTimeout( foo, 1000 //这里设置延时数 );
18、setTimeout与setInterval有何区别?
①setTimeout和setInterval的语法相同。它们都有两个参数,一个是将要执行的代码字符串,还有一个是以毫秒为单位的时间间隔,当过了那个时间段之后就将执行那段代码。
②不过这两个函数还是有区别的,setInterval在执行完一次代码之后,经过了那个固定的时间间隔,它还会自动重复执行代码,而setTimeout只执行一次那段代码。
19、你在js中用过array吗?如果用过,array中添加数据用什么方法?
在尾部添加使用push();
在头部添加使用unshift();
在任意位置添加使用splice(),但要注意把它的删除个数设置为0;
array详细介绍请看下文链接
JS中数组对象详解
20、简述javascript的优缺点。
优点:简单易用,与Java有类似的语法,可以使用任何文本编辑工具编写,只需要浏览器就可执行程序,并且事先不用编译,逐行执行,无需进行严格的变量声明,而且内置大量现成对象,编写少量程序可以完成目标;
缺点:不适合开发大型应用程序;
21、Javascript有哪些内置对象?
只有Math和Global(在浏览器环境中,Global就是Window)
22、列举Javascript的本地对象。
Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError
23、javascript的typeof返回哪些数据类型
object number function boolean undefind string
24、例举3种强制类型转换和2种隐式类型转换?
强制(parseInt,parseFloat,number)
隐式(==–===)
25、IE和DOM事件流的区别
①执行顺序不一样、
②参数不一样
③事件加不加on
④this指向问题
26、事件绑定和普通事件有什么区别
①事件绑定就是针对dom元素的事件,绑定在dom元素上
②普通事件即为非针对dom元素的事件
27、事件委托是什么
利用事件冒泡的原理,让自己的所触发的事件,由他的父元素代替执行!
通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。
例子请看以下链接
JS中的事件委托
28、闭包是什么,有什么特性,对页面有什么影响
什么是闭包
“官方”的解释:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。
通俗的讲就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。
闭包的特性:
①.封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;
②.持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在;
对页面的影响
使用闭包会占有内存资源,过多的使用闭包会导致内存溢出等。
详细请看以下推荐链接
深入理解JavaScript的闭包特性 如何给循环中的对象添加事件
29、javascript的本地对象,内置对象和宿主对象
①本地对象为array obj regexp等可以new实例化
②内置对象为gload Math 等不可以实例化的
③宿主为浏览器自带的document,window 等
30、编写一个数组去重的方法
思路:
1.创建一个新的数组存放结果
2.创建一个空对象
3.for循环时,每次取出一个元素与对象进行对比,如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。
说明:至于如何对比,就是每次从原数组中取出一个元素,然后到对象中去访问这个属性,如果能访问到值,则说明重复。
代码如下:
Array.prototype.unique3=function(){ var res=[]; var json={}; for(var i=0; i < this.length; i++){ if(!json[this[i]]){ res.push(this[i]); json[this[i]]=1; } } return res; } var arr=[112,112,34,'你好',112,112,34,'你好','str','str1']; alert(arr.unique3());
31、this对象的理解
①this总是指向函数的直接调用者(而非间接调用者);
②如果有new关键字,this指向new出来的那个对象;
③在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;
32、eval是做什么的?
①它的功能是把对应的字符串解析成JS代码并运行;
②应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
③由JSON字符串转换为JSON对象的时候可以用eval,var obj=eval('('+ str +')');
33、new操作符具体干了什么呢?
①创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
②属性和方法被加入到 this 引用的对象中。
③新创建的对象由 this 所引用,并且最后隐式的返回 this 。
34、call() 和 apply() 的区别和作用?
①apply()函数有两个参数:第一个参数是上下文,第二个参数是参数组成的数组。如果上下文是null,则使用全局对象代替。
如:function.apply(this,[1,2,3]);
②call()的第一个参数是上下文,后续是实例传入的参数序列。
如:function.call(this,1,2,3);
如何获取UA
JS代码
function whatBrowser() { document.Browser.Name.value=navigator.appName; document.Browser.Version.value=navigator.appVersion; document.Browser.Code.value=navigator.appCodeName; document.Browser.Agent.value=navigator.userAgent; }
35、请解释一下 JavaScript 的同源策略
概念:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。
这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。指一段脚本只能读取来自同一来源的窗口和文档的属性。
为什么要有同源限制?
我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
36、请描述一下 cookies,sessionStorage 和 localStorage 的区别?
cookie在浏览器和服务器间来回传递。 sessionStorage和localStorage不会
sessionStorage和localStorage的存储空间更大;
sessionStorage和localStorage有更多丰富易用的接口;
sessionStorage和localStorage各自独立的存储空间;
小结
在互联网上,图像和链接则是通过URL唯一确定信息资源的位置。URL分为绝对URL和相对URL。通过使用<img />标记在浏览器中显示一张图像。超文本具有的链接能力,可层层链接相关文件,这种具有超链接能力的操作,称为超链接。链接文档中的特定位置也称为锚点,定义锚点和超链接都使用<a>标记。图像地图是带有可点击区域的图像,每个区域是一个相关的超级链接。video和audio这两个HTML5新增加的元素,它们分别用来处理视频与音频数据,使得多媒体播放再也不需要安装插件了。
习题
1.audio元素中src属性的作用是(C)
A.提供播放、暂停和音量控件 B.循环播放
C.制定要播放音频的URL D.插入一段替换内容
*请认真填写需求信息,我们会在24小时内与您取得联系。