单线程
只有一个线程,同一时间只能做一件事
原因:避免DOM渲染的冲突
浏览器需要渲染DOM
JS可以修改DOM结果
JS执行的时候,浏览器DOM渲染会暂停
两段JS也不能同时执行(修改DOM就冲突)
webworker支持多线程,但是不能访问DOM,本质JS还是单线程
解决方案:异步
case1
{ ???var i, sum = 0 ???for(i = 0; i < 100000000; i++) { ???????sum += i ???} ???console.log(sum)}
case2
{ ???console.log(1) ???alert(‘a‘) ???console.log(2)}
分析:JS执行阻塞DOM渲染,出现卡顿。因为js是单线程
case3
{ ???console.log(100) ???setTimeout(function(){ ???????console.log(200) ???},100) ???console.log(300)}
分析:JS是单线程的,第一行打印100,第二行setTimeout是异步,暂时不执行,先往下执行,第三行打印300,代码结束。然后发现setTimout没执行,那么打印200。
event-loop
事件轮询,JS实现异步的具体解决方案
同步代码,直接执行
异步函数先放在异步队列中
待同步函数执行完毕,轮询执行异步队列的函数
case1
{ ???console.log(100) ???setTimeout(function(){ ???????console.log(200) ???},100) ???console.log(300)}
分析:同步代码,直接执行,第一行和第三行是同步代码,直接打印100和300,第二行是异步代码,先放入异步队列。同步代码执行完毕,这时候查看异步队列,执行setTimeout打印200
case2
{ ???console.log(100) ???setTimeout(function(){ ???????console.log(200) ???},100) ???setTimeout(function(){ ???????console.log(300) ???}) ???console.log(400)}
分析:同步代码直接执行,第一行和第四行直接执行,打印100和400。
同步代码执行完毕,查看异步队列。这时候有2个setTimeout函数,第三行会直接放入异步队列中,那么打印300。
而第二行100ms之后才被放入异步队列中,打印200
case3
{ ???$.ajax({ ???????url:‘‘, ???????success:function(result){ ???????????console.log(‘a‘) ???????} ???}) ???setTimeout(function(){ ???????console.log(‘b‘) ???},100) ???setTimeout(function(){ ???????console.log(‘c‘) ???}) ???console.log(‘d‘)}
结果: d c a b或者 d c b a
jQuery的Deferred
dtd.resolve/dtd.reject
dtd.then/dtd.done/dtd/fail
case1
function waitHandle() { ???var dtd = $.Deferred() ???!function(dtd){ ???????var task = function() { ???????????console.log(‘执行完毕‘) ???????????dtd.resolve() ???????} ???????setTimeout(task, 2000) ???}(dtd) ???return dtd}waitHandle() ???.then(function(){ ???????console.log(‘success‘) ???})
case2
function waitHandle() { ???var dtd = $.Deferred() ???!function(dtd){ ???????var task = function() { ???????????console.log(‘执行完毕‘) ???????????dtd.resolve() ???????} ???????setTimeout(task, 2000) ???}(dtd) ???return dtd.promise()}var w = waitHandle() ???$.when(w).then(function(){ ???????console.log(‘success‘) ???})
注意:这2个case不同之处一个case是返回dtd还有一个返回dtd.promise()对象。
第一个case w.reject()不会报错,但是会出现代码混乱
第二个case w.reject()会报错,无法干预代码
Promise
回顾下语法
case
{ ???function loadImg(src){ ???????return new Promise((resolve, reject)=>{ ???????????let img = document.createElement(‘img‘) ???????????img.onload = () => resolve(img) ???????????img.onerror = () => reject() ???????????img.src = src ???????}) ???} ???const src = ‘https://....jpeg‘ ???var res = loadImg(src) ???res.then(img => { ???????console.log(img) ???}, () => { ???????console.log(‘fail‘) ???})}
异常捕获
使用catch统一捕获异常
case
{ ???function loadImg(src){ ???????return new Promise((resolve, reject)=>{ ???????????let img = document.createElement(‘img‘) ???????????img.onload = () => resolve(img) ???????????img.onerror = () => reject(‘异常‘) ???????????img.src = src ???????}) ???} ???const src = ‘https://....jpeg‘ ???var res = loadImg(src) ???res.then(img => { ???????console.log(img) ???}).catch(e => { ???????console.log(e) ???})}
多个串联
链式操作部分代码
const res = loadImg(src) ???const res2 = loadImg(src2) ???res.then(() => { ???????console.log(‘one‘) ???????return res2 ???}).then(() => { ???????console.log(‘two‘) ???}).catch(e => { ???????console.log(e) ???})
Promise.all和Promise.race
Promise.all接收一个promise对象的数组,待全部完成之后,统一执行then
Promise.race接收一个promise对象的数组,只要一个完成,就执行then
async/await
直接只用同步写法
case
{ ???function loadImg(src){ ???????return new Promise((resolve, reject)=>{ ???????????let img = document.createElement(‘img‘) ???????????img.onload = () => resolve(img) ???????????img.onerror = () => reject(‘异常‘) ???????????img.src = src ???????}) ???} ???const src = ‘https://....jpeg‘ ???const src2 = ‘https://...jpg‘ ???????async function load() { ???????const res = await loadImg(src) ???????console.log(res) ???????const res2 = await loadImg(src2) ???????console.log(res2) ???} ???load()}
虽然是同步写法,但是使用了Promise,并没有改变JS时单线程,异步的本质
JS高级-异步
原文地址:https://www.cnblogs.com/sonwrain/p/10540416.html