所谓单线程,无非就是同步队列和异步队列,js代码是自上向下执行的,在主线程中立即执行的就是同步任务,比如简单的逻辑操作及函数,而异步任务不会立马立马执行,会挪步放到到异步队列中,比如ajax、promise、事件、计时器等等。
也就是先执行同步,主线程结束后再按照异步的顺序再次执行。
二、时间循环(Event Loop)
Event Loop是什么?中文翻译是事件循环,等待主线程中任务全部完成后,再回来把异步队列中任务放到主程序中运行,这样反复的循环,就是事件循环。
b14d903a712b31c34f347ba7d64b697e.png
先来看组代码
console.log('开始111') setTimeout(function () {console.log('setTimeout111') }, 0) Promise.resolve().then(function () {console.log('promise111') }).then(function () {console.log('promise222') }) console.log('开始222')
打印 “开始111”,再打印“开始222”。
中途的三个异步,进入到了异步队列,等待同步执行完(打印完),返回来再执行异步,所以是后打印出来。
打印的结果先放一放,我们稍后回来再说。现在我们中途插播一段知识点:
三、宏观任务和微观任务(先执行微观任务,再执行宏观任务):
在事件循环中,每进行一次循环操作称为tick,tick 的任务处理模型是比较复杂的,里边有两个词:分别是 Macro Task (宏任务)和 Micro Task(微任务)。
简单来说:
宏观任务主要包含:setTimeout、setInterval、script(整体代码)、I/O、UI 交互事件、setImmediate(Node.js 环境)
微观任务主要包括:Promise、MutaionObserver、process.nextTick(Node.js 环境)
规范:先执行微观任务,再执行宏观任务
那么我们知道了,Promise 属于微观任务, setTimeout、setInterval 属于宏观任务,先执行微观任务,等微观任务执行完,再执行宏观任务。所以我们再看一下这个代码:
console.log('开始111') setTimeout(function () {console.log('setTimeout111') }, 0) Promise.resolve().then(function () {console.log('promise111') }).then(function () {console.log('promise222') }) console.log('开始222')
我们按照步骤来分析下:
1、遇到同步任务,直接先打印 “开始111”。
2、遇到异步 setTimeout ,先放到队列中等待执行。
3、遇到了 Promise ,放到等待队列中。
4、遇到同步任务,直接打印 “开始222”。
5、同步执行完,返回执行队列中的代码,从上往下执行,发现有宏观任务 setTimeout 和微观任务 Promise ,那么先执行微观任务,再执行宏观任务。
所以打印的顺序为:开始111 、开始222 、 promise111 、 promise222 、 setTimeout111 。
同理,我们再来分析一个代码:
console.log('开始111')setTimeout(function () { console.log('timeout111')})new Promise(resolve =>{ console.log('promise111') resolve() setTimeout(() =>console.log('timeout222'))}).then(function () { console.log('promise222')})console.log('开始222')
分析一下:
1、遇到同步代码,先打印 “开始111” 。
2、遇到setTimeout异步,放入队列,等待执行 。
3、中途遇到Promise函数,函数直接执行,打印 “promise111”。
4、遇到setTimeout ,属于异步,放入队列,等待执行。
5、遇到Promise的then等待成功返回,异步,放入队列。
6、遇到同步,打印 “开始222”。
7、执行完,返回,将异步队列中的代码,按顺序执行。有一个微观任务,then后的,所以打印 “promise222”,再执行两个宏观任务 “timeout111” “timeout222”。
所以,打印的顺序为:开始111 、 promise111 、 开始222 、 promise222 、 timeout111 、 timeout222 .
先执行主任务,把异步任务放入循环队列当中,等待主任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行,就是事件循环机制。
我给你一个原来我做的例子,这个例子里面有你需要的东西。请参考。这个例子你把他全部复制下来,保存成htm后缀的文件,然后用IE6调试,没有任何问题。他可以动态生成控件,动态调用,动态删除,动态执行你动态生成控件里面的方法。
祝好运
---------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Split BinaryTree Extends</title>
<script language='javascript'>
//全局变量定义:注意所有的层数都是以数组下标的方式对应-------------------------------------
/*定义描述:层id表示方法 ("div_" + 层数[divNumber])
头bool下拉列表id表示方法 ("selectHead_" + 层数[divNumber])
*/
var divNumber = 0 //当前有多少层,0表示第一层,也就是初始的那一层,这里的层指实际的层数
var divLeft = 0 //当前的左边距
var divTop= 0 //当前的上边距
//----------------------------------------------------------------------------------------
function createFirstExpression()//创建第1层,这个方法只有boolSelect_0这个对象用
{
if(divNumber == 0) //如果只有仅仅一层的话,那么建立第二层
{
//创建BoolOption选项第1层
divNumber += 1
var firstExpressionBoolean = document.createElement("div")
firstExpressionBoolean.id = "div_1"
var selectHead = document.createElement("select")
selectHead.id = "selectHead_1"
var strValue = document.getElementById("boolSelect_0").options[document.getElementById("boolSelect_0").selectedIndex].text
var opt = new Option(strValue)
selectHead.add(opt)
selectHead.style.setAttribute("position", "absolute") //绝对于firstExpressionBoolean
selectHead.style.setAttribute("left", "0px")
firstExpressionBoolean.appendChild(selectHead)
firstExpressionBoolean.style.setAttribute("position", "relative")
firstExpressionBoolean.style.setAttribute("top", "5px")//相对于mainDiv
firstExpressionBoolean.style.setAttribute("left", "-45px")//相对于mainDiv
firstExpressionBoolean.style.setAttribute("width", "310px")
document.getElementById("mainDiv").appendChild(firstExpressionBoolean)
//创建Condition选项第2层
divNumber += 1
var secondExpressionCondition = document.createElement("div")
secondExpressionCondition.id = "div_2"
secondExpressionCondition.appendChild(bornCheckBox("2"))
secondExpressionCondition.appendChild(bornTextValue("2"))
secondExpressionCondition.appendChild(bornConditionSelect("2"))
secondExpressionCondition.appendChild(bornBoolSelect("2"))
secondExpressionCondition.style.setAttribute("position", "relative")
secondExpressionCondition.style.setAttribute("top", "30px")//相对于mainDiv
secondExpressionCondition.style.setAttribute("left", "0px")//相对于mainDiv
secondExpressionCondition.style.setAttribute("width", "310px")
document.getElementById("mainDiv").appendChild(secondExpressionCondition)
}
else//如果已经创建了3层,那么现在可以开始分离数据,进行树形结构创建
{
createTwoChild(0)//创建三层,插入当前位置
}
}
function bornCheckBox(CurrentDivNumber) //创建复选框,传的是当前要创建的这一层的参数,也就是这一层的参数要赋予值给这个id控件
{
var _checkBox = document.createElement("input")
_checkBox.setAttribute("type", "checkbox")
_checkBox.setAttribute("value", "checked")
_checkBox.style.setAttribute("position", "absolute") //这个是绝对定位定为于当前层
_checkBox.style.setAttribute("left", "10px")
_checkBox.id = "checkBox_" + CurrentDivNumber
return _checkBox
}
function bornTextValue(CurrentDivNumber)//创建Not文本
{
var divTextValue = document.createElement("divTextValue") //用层定位
divTextValue.id = "divTextValue_" + CurrentDivNumber
divTextValue.style.setAttribute("position", "absolute") //这个是绝对定位定为于当前层
divTextValue.style.setAttribute("left", "30px")
var newText= document.createTextNode("not")
divTextValue.appendChild(newText)
return divTextValue
}
function bornConditionSelect(CurrentDivNumber) //创建条件下拉
{
var conditionSelect = document.createElement("select")
for(var i = 1i <6i++) //只是显示一些数据
{
var opt = new Option("cond" + i)
conditionSelect.add(opt)
}
conditionSelect.style.setAttribute("position", "absolute") //绝对于当前层
conditionSelect.style.setAttribute("left", "54px")
conditionSelect.style.setAttribute("width", "178px")
conditionSelect.id = "conditionSelect_" + CurrentDivNumber
return conditionSelect
}
function bornBoolSelect(CurrentDivNumber) //创建bool下拉
{
var boolSelect = document.createElement("select")
var opt = new Option(" ")
boolSelect.add(opt)
var optAND = new Option("AND")
boolSelect.add(optAND)
var optOR = new Option("OR")
boolSelect.add(optOR)
var optDELETE = new Option("DEL")
boolSelect.add(optDELETE)
boolSelect.style.setAttribute("position", "absolute") //绝对于当前层
boolSelect.style.setAttribute("left", "245px")
boolSelect.id = "boolSelect_" + CurrentDivNumber
boolSelect.attachEvent("onchange",function(){createTwoChild(CurrentDivNumber)})
return boolSelect
}
function bornOnlyOneHeadEX(CurrentDivNumber, InsertLeft, InsertTop, choseNumber)//创建头选项,choseNumber就是你的父行选择的什么选项
{
var selectHeadDiv = document.createElement("div")
var selectHead = document.createElement("select")
var opt = new Option(" ")
selectHead.add(opt)
var optAND = new Option("AND")
selectHead.add(optAND)
var optOR = new Option("OR")
selectHead.add(optOR)
var optDELETE = new Option("DEL")
selectHead.add(optDELETE)
selectHead.style.setAttribute("position", "absolute") //绝对于当前层
selectHead.style.setAttribute("left", "0px")
selectHead.id = "selectHead_" + CurrentDivNumber
selectHeadDiv.style.setAttribute()
selectHeadDiv.appendChild(selectHead)
selectHeadDiv.style.setAttribute("position", "relative")
selectHeadDiv.style.setAttribute("top", InsertTop)//相对于mainDiv
selectHeadDiv.style.setAttribute("left", InsertLeft) //相对于mainDiv
selectHeadDiv.style.setAttribute("width", "310px")
selectHead.selectedIndex = choseNumber
selectHeadDiv.id = "div_" + CurrentDivNumber //当前层的序号
return selectHeadDiv
}
function changeAllDivTop(InsertDIVNumber)//插入需要进入的层的位置,也就是说你插入了以后从这个插入层的i+1到Max(i)的所有层增加,这个只控制页面
{
if(InsertDIVNumber <divNumber)//选择的不是最后一行
{
var x = parseInt(divNumber)
var lowerLevel = parseInt(parseInt(InsertDIVNumber) + 1)
for(x=divNumberx >= lowerLevelx--)
{
var strTop = document.getElementById("div_" + x).style.top
var strTopNumber = strTop.substr(0, strTop.length - 2)
strTopNumber = 75 + parseInt(strTopNumber)
var currentTop = strTopNumber + "px"
//改变层内的每一个元素的id
if(document.getElementById("div_" + x).childNodes.length == 4)
{
document.getElementById("checkBox_" + x).id = "checkBox_" + (parseInt(x) + 2) //改变check,让他和层标志对应
document.getElementById("divTextValue_" + x).id = "divTextValue_" + (parseInt(x) + 2) //改变not
document.getElementById("conditionSelect_" + x).id = "conditionSelect_" + (parseInt(x) + 2)//改变condSelect
var tempNumber = parseInt(x) + 2
document.getElementById("boolSelect_" + x).onchange = null
document.getElementById("boolSelect_" + x).attachEvent("onchange",function(){createTwoChild(tempNumber)})//修改参数传递
document.getElementById("boolSelect_" + x).id = "boolSelect_" + (parseInt(x) + 2) //改变boolSelect
}
else if(document.getElementById("div_" + x).childNodes.length == 1)
{
document.getElementById("selectHead_" + x).id = "selectHead_" + (parseInt(x) + 2)//改变selectHead
}
//最后来移动层和改变层的标识
document.getElementById("div_" + x).style.top = currentTop
document.getElementById("div_" + x).id = "div_" + (parseInt(x) + 2)//向下替换层数坐标
}
}
else
{}
}
function createOnlyOneDiv(InsertDIVNumber, InsertLeft, InsertTop) //创建只有一层的check,text,select,相对于MainDiv的left,top
{
var ExpressionCondition = document.createElement("div")
ExpressionCondition.id = "div_" + InsertDIVNumber
ExpressionCondition.appendChild(bornCheckBox(InsertDIVNumber))
ExpressionCondition.appendChild(bornTextValue(InsertDIVNumber))
ExpressionCondition.appendChild(bornConditionSelect(InsertDIVNumber))
ExpressionCondition.appendChild(bornBoolSelect(InsertDIVNumber))
ExpressionCondition.style.setAttribute("position", "relative")
ExpressionCondition.style.setAttribute("top", InsertTop)//相对于mainDiv
ExpressionCondition.style.setAttribute("left", InsertLeft) //相对于mainDiv
ExpressionCondition.style.setAttribute("width", "310px")
return ExpressionCondition
}
function createTwoChild(InsertDIVNumber) //创建2个子结点,该子结点又插入的该层位置决定,描述同
{
changeAllDivTop(InsertDIVNumber) //调整下面的位置,多调整2层出来
var parentPureLeft = document.getElementById("div_" + InsertDIVNumber).style.left//获取插入后,创建三个层里面的中间的一层的left
var parentLeft = parentPureLeft.substr(0, parentPureLeft.length - 2)
var parentPureTop = document.getElementById("div_" + InsertDIVNumber).style.top//获取插入后,创建三个层里面的中间的一层的top
var parentTop = parentPureTop.substr(0, parentPureTop.length - 2)
var choseNumber = 0
if(document.getElementById("boolSelect_" + InsertDIVNumber).options[document.getElementById("boolSelect_" + InsertDIVNumber).selectedIndex].text=="AND")
{
choseNumber = 1 //选择的AND选项
}
else
{
choseNumber = 2 //选择的OR选项
}
document.getElementById("mainDiv").removeChild(document.getElementById("div_" + InsertDIVNumber)) //获取完插入这行的信息后,删除该行
//创建子节点
var firstDIV = createOnlyOneDiv(InsertDIVNumber, ((parseInt(parentLeft) + 55)+"px"), (parentTop+"px")) //第一层就是原来的位置
var secondDIV = bornOnlyOneHeadEX((parseInt(InsertDIVNumber) + 1), (parseInt(parentLeft) + 15) + "px", (parseInt(parentTop) + 30)+"px", choseNumber) //第二层bool选项层
var thirdDIV = createOnlyOneDiv((parseInt(InsertDIVNumber) + 2), ((parseInt(parentLeft) + 55)+"px"), (parseInt(parentTop) + 60)+"px")//第三层
document.getElementById("mainDiv").appendChild(firstDIV)
document.getElementById("mainDiv").appendChild(secondDIV)
document.getElementById("mainDiv").appendChild(thirdDIV)
divNumber = parseInt(divNumber ) + 2
}
</script>
</head>
<body>
<center>
<div id="mainDiv">
<div id="div_0" style="position:relativeleft:0pxtop:0pxwidth:310px">
<input type="checkbox" id="checkBox_0" />not
<select id="condSelect_0" style="width:180px">
<option value="0">cond1</option>
<option value="1">cond2</option>
<option value="2">cond3</option>
<option value="3">cond4</option>
<option value="4">cond5</option>
</select>
<select id="boolSelect_0" onchange="createFirstExpression()">
<option value=""> </option>
<option value="1">AND</option>
<option value="2">OR </option>
</select>
</div>
</div>
</center>
</body>
</html>