• JS高级-异步


    单线程

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

      原因:避免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时单线程,异步的本质

  • 相关阅读:
    软件设计师考试知识点总结
    HTML和CSS
    JavaScript核心知识点
    操作系统--页面置换算法(缺页数计算)
    中标麒麟系统远程桌面连接
    数据结构 图
    数据结构 二叉树
    MATLAB 大数据剔除坏值
    PTA 邻接表存储图的广度优先遍历(20 分)
    PTA 邻接矩阵存储图的深度优先遍历
  • 原文地址:https://www.cnblogs.com/sonwrain/p/10540416.html
Copyright © 2020-2023  润新知