原型
异步
一、什么是单线程,和异步有什么关系
单线程:只有一个线程,同一时间只能做一件事
原因:避免DOM渲染的冲突
解决方案:异步
- 浏览器需要渲染DOM
- JS可以修改DOM结构
- JS执行的时候,浏览器DOM渲染会暂停
- 两端JS也不能同时执行(都修改DOM就冲突了)
- webworker支持多线程,但是不能访问DOM
- 问题一:没按照书写方式执行,可读性差
- 问题二:callback中不容易模块化
二、什么是event-loop
setTimeout(function(){
console.log(1);
},100); //100ms之后才放入异步队列中,目前异步队列是空的
setTimeout(function(){
console.log(2); //直接放入异步队列
})
console.log(3) //直接执行
//执行3之后,异步队列中只有2,把2拿到主线程执行,2执行完之后,异步队列中并没有任务,所以一直轮询异步队列,直到100ms之后1放入异步队列,将1拿到主线程中执行
$.ajax({
url:'./data.json',
success:function(){ //网络请求成功就把success放入异步队列
console.log('a');
}
})
setTimeout(function(){
console.log('b')
},100)
setTimeout(function(){
console.log('c');
})
console.log('d')
//打印结果:
//d //d
//c //c
//a //b
//b //a
//真实环境不会出现dacb
三、是否用过jQuery的Deferred
var ajax = $.ajax({
url:'./data.json',
success:function(){
console.log('success1');
console.log('success2');
console.log('success3');
},
error:function(){
console.log('error');
}
})
console.log(ajax); //返回一个XHR对象
var ajax = $.ajax('./data.json');
ajax.done(function(){
console.log('success1')
})
.fai(function(){
console.log('fail')
})
.done(function(){
console.log('success2');
})
console.log(ajax); //deferred对象
var ajax = $.ajax('./data.json');
ajax.then(function(){
console.log('success1')
},function(){
console.log('error1');
})
.then(function(){
console.log('success2');
},function(){
console.log('error');
})
//使用
var w = waithandle()
w.then(function(){
console.log('ok1');
},function(){
console.log('err2');
})
.then(function(){
console.log('ok2');
},function(){
console.log('err2');
})
//还有w.wait w.fail
使用jQuery Deferred
//给出一段非常简单的代码,使用setTimeout函数
var wait = function(){
var task = function(){
console.log('执行完成');
}
setTimeout(task,2000)
}
wait();
//新增需求:要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤
function waitHandle(){
var dtd = $.Deferred();//创建一个deferred对象
var wait = function(dtd){ // 要求传入一个deferred对象
var task = function(){
console.log("执行完成");
dtd.resolve(); //表示异步任务已完成
//dtd.reject() // 表示异步任务失败或者出错
};
setTimeout(task,2000);
return dtd;
}
//注意,这里已经要有返回值
return wait(dtd);
}
/*
*总结:dtd的API可分成两类,用意不同
*第一类:dtd.resolve dtd.reject
*第二类:dtd.then dtd.done dtd.fail
*这两类应该分开,否则后果严重!
*可以在上面代码中最后执行dtd.reject()试一下后果
*/
使用dtd.promise()
function waitHandle(){
var dtd = $.Deferred();
var wait = function(){
var task = function(){
console.log('执行完成');
dtd.resolve();
}
setTimeout(task,2000)
return dtd.promise(); //注意这里返回的是promise,而不是直接返回deferred对象
}
return wait(dtd)
}
var w = waitHandle(); //promise对象
$.when(w).then(function(){
console.log('ok1');
},function(){
console.log('err1');
})
/*
只能被动监听,不能干预promise的成功和失败
*/
要想深入了解它,就需要知道它的前世今生
四、Promise的基本使用和原理
基本语法回顾
异常捕获
//规定:then只接受一个函数,最后统一用catch捕获异常
多个串联
var scr1 = 'https://www.imooc.com/static/img/index/logo_new.png';
var result1 = loadImg(src1);
var src2 = 'https://www.imooc.com/static/img/index/logo_new.png';
var result2 = loadImg(src2);
result1.then(function(img1) {
console.log('第一个图片加载完成', img1.width);
return result2;
}).then(function(img2) {
console.log('第二个图片加载完成', img2.width);
}).catch(function(ex) {
console.log(ex);
})
Promise.all和Promise.race
//Promise.all接收一个promise对象的数组
//待全部完成后,统一执行success
Promise.all([result1, result2]).then(datas => {
//接收到的datas是一个数组,依次包含了多个promise返回的内容
console.log(datas[0]);
console.log(datas[1]);
})
//Promise.race接收一个包含多个promise对象的数组
//只要有一个完成,就执行success
Promise.race([result1, result2]).then(data => {
//data即最先执行完成的promise的返回值
console.log(data);
})
Promise标准
promise必须实现then这个方法
then()必须接收两个函数作为标准
then
五、介绍一下async/await(和Promise的区别、联系)
六、总结一下当前JS结局异步的方案
虚拟DOM
vdom 是什么?为何会存在 vdom?
- virtual dom,虚拟DOM
- 用JS模拟DOM结构
- DOM变化的对比,放在JS层来做(图灵完备语言:能实现各种逻辑的语言)
- 提高重绘性能
<ul id="list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
</ul>
{
tag: 'ul',
attrs: {
id: 'list'
},
children: [{
tag: 'li',
attrs: { className: 'item' },
children: ['item1']
},
{
tag: 'li',
attrs: { className: 'item' },
children: ['item2']
}
]
}
//className代替class,因为class是js的保留字
浏览器最耗费性能就是DOM操作,DOM操作非常昂贵
现在浏览器执行JS速度非常快
这就是vdom存在的原因
//将该数据展示成一个表格
//随便修改一个信息,表格也随着修改
[
{
name: 'zhangsan',
age: 20,
address: 'beijing'
},
{
name: 'lisi',
age: 21,
address: 'shanghai'
},
{
name: 'wangwu',
age: 22,
address: 'guangzhou'
}
]
//渲染函数
funciton render(data) {
//此处省略n行
}
//修改信息
$('#btn-change').click(function(){
data[1].age = 30;
data[2].address = 'shenzhen';
render(data);
})
//初始化时渲染
render(data)
//render函数具体写法
function render(data) {
$container = $("#container");
//清空现有内容
$container.html('');
//拼接table
var $table = $('<table>')
$table.append($('<tr><td>name</td><td>age</td><td>address</td></tr>'))
data.forEach(item => {
$table.append($('<tr><td>' + item.name + '</td><td>' + item.age + '</td><td>' + item.address + '</td></tr>'))
$container.append($table)
});
}
//只执行了一次渲染,相对来说还是比较高效的
//DOM渲染是最昂贵的,只能尽量避免渲染
- DOM操作是“昂贵”的,JS运行效率高
- 尽量减少DOM操作,而不是"推倒重来"(清空重置)
- 项目越复杂,影响就越严重
- vdom可解决这个问题
var div = document.createElement('div');
var item,result = '';
for(item in div){
result += '|' + item;
}
console.log(result);
//浏览器默认创建出来的DOM节点,属性是非常多的
//result
|align|title|lang|translate|dir|dataset|hidden|tabIndex|accessKey|draggable|spellcheck|autocapitalize|contentEditable|isContentEditable|inputMode|offsetParent|offsetTop|offsetLeft|offsetWidth|offsetHeight|style|innerText|outerText|onabort|onblur|oncancel|oncanplay|oncanplaythrough|onchange|onclick|onclose|oncontextmenu|oncuechange|ondblclick|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|ondurationchange|onemptied|onended|onerror|onfocus|oninput|oninvalid|onkeydown|onkeypress|onkeyup|onload|onloadeddata|onloadedmetadata|onloadstart|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onpause|onplay|onplaying|onprogress|onratechange|onreset|onresize|onscroll|onseeked|onseeking|onselect|onstalled|onsubmit|onsuspend|ontimeupdate|ontoggle|onvolumechange|onwaiting|onwheel|onauxclick|ongotpointercapture|onlostpointercapture|onpointerdown|onpointermove|onpointerup|onpointercancel|onpointerover|onpointerout|onpointerenter|onpointerleave|nonce|click|focus|blur|namespaceURI|prefix|localName|tagName|id|className|classList|slot|attributes|shadowRoot|assignedSlot|innerHTML|outerHTML|scrollTop|scrollLeft|scrollWidth|scrollHeight|clientTop|clientLeft|clientWidth|clientHeight|attributeStyleMap|onbeforecopy|onbeforecut|onbeforepaste|oncopy|oncut|onpaste|onsearch|onselectstart|previousElementSibling|nextElementSibling|children|firstElementChild|lastElementChild|childElementCount|onwebkitfullscreenchange|onwebkitfullscreenerror|setPointerCapture|releasePointerCapture|hasPointerCapture|hasAttributes|getAttributeNames|getAttribute|getAttributeNS|setAttribute|setAttributeNS|removeAttribute|removeAttributeNS|hasAttribute|hasAttributeNS|toggleAttribute|getAttributeNode|getAttributeNodeNS|setAttributeNode|setAttributeNodeNS|removeAttributeNode|closest|matches|webkitMatchesSelector|attachShadow|getElementsByTagName|getElementsByTagNameNS|getElementsByClassName|insertAdjacentElement|insertAdjacentText|insertAdjacentHTML|requestPointerLock|getClientRects|getBoundingClientRect|scrollIntoView|scrollIntoViewIfNeeded|animate|computedStyleMap|before|after|replaceWith|remove|prepend|append|querySelector|querySelectorAll|webkitRequestFullScreen|webkitRequestFullscreen|scroll|scrollTo|scrollBy|createShadowRoot|getDestinationInsertionPoints|ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|DOCUMENT_POSITION_DISCONNECTED|DOCUMENT_POSITION_PRECEDING|DOCUMENT_POSITION_FOLLOWING|DOCUMENT_POSITION_CONTAINS|DOCUMENT_POSITION_CONTAINED_BY|DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC|nodeType|nodeName|baseURI|isConnected|ownerDocument|parentNode|parentElement|childNodes|firstChild|lastChild|previousSibling|nextSibling|nodeValue|textContent|hasChildNodes|getRootNode|normalize|cloneNode|isEqualNode|isSameNode|compareDocumentPosition|contains|lookupPrefix|lookupNamespaceURI|isDefaultNamespace|insertBefore|appendChild|replaceChild|removeChild|addEventListener|removeEventListener|dispatchEvent
vdom如何应用,核心API是什么
一个实现vdom
的库,vue升级2.0借鉴了snabbdom
的算法
var container = document.getElementById('container')
var vnode = h('div#container.two.classes', { on: { click: someFn } }, [
h('span', { style: { fontWeight: 'bold' }, 'This is bold' }),
'and this is just normal text',
h('a', { props: { href: '/foo' } }, 'I\'ll take you places')
])
//patch into empty DOM element - this modifies the DOM as a side effect
patch(container, vnode)
var newVnode = h('div#container.two.classes', { on: { click: anotherEventHandle } }, [
h('span', { style: { fontWeight: 'normal', fontStyle: 'italic' } }, 'this is now italic type'),
'and this is still just normal text',
h('a', { props: { href: '/bar' } }, 'I\'ll take you places')
])
//send `patch` invocation
patch(vnode, newVnode); //Snabbdom efficiently updates the old view to the new state
{
tar: 'ul',
attrs: {
id: 'list'
},
children: [
{
tag: 'li',
attrs: {
className: 'item',
children: ['item1']
}
},
{
tag: 'li',
attrs: {
className: 'item'
},
children: ['item2']
}
]
}
var vnode = h('ul#list', {}, [
h('li.item', {}, 'Item1'),
h('li.item', {}, 'Item')
])
var vnode = h('ul#list', {}, [
h('li.item', {}, 'Item1'),
h('li.item', {}, 'Item2')
])
var container = document.getElementById('container')
patch(container, vnode)
//模拟改变
var btnChange = document.getElementById('btn-change')
btnChange.addEventListener('click', function() {
var newVnode = h('ul#list', {}, [
h('li.item', {}, 'Item 111'),
h('li.item', {}, 'Item 222'),
h('li.item', {}, 'Item 333')
])
patch(vnode, newVnode)
})
介绍一下diff算法
MVVM和vue
说一下对 MVVM
的理解
组件化和React
hybrid
未完待续,每日更新