原型

异步

一、什么是单线程,和异步有什么关系

单线程:只有一个线程,同一时间只能做一件事

原因:避免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

未完待续,每日更新

12-25 16:32