zoukankan      html  css  js  c++  java
  • 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时单线程,异步的本质

  • 相关阅读:
    ThinkPHP 3.2.2 实现持久登录 ( 记住我 )
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 17 电话号码的字母组合
  • 原文地址:https://www.cnblogs.com/sonwrain/p/10540416.html
Copyright © 2011-2022 走看看