美文网首页
初步浅析浏览器异步机制

初步浅析浏览器异步机制

作者: BertieSama | 来源:发表于2017-01-11 01:04 被阅读0次

    先说一下JavaScript异步的概念:
    首先因为js是单线程的语言,且没有异步的特性。

    然后js的宿主环境是在浏览器端,js的异步操作是浏览器来提供的,浏览器的js引擎在执行js代码的时候也只是会提供一条线程去执行,真抠...并且!js(主栈列内的js,后文解析什么是主栈列)代码执行会阻塞渲染线程和浏览器事件触发线程,后面这两个线程是属于浏览器内的常驻线程,当然还有其他的比如说http请求线程,那么比如说我们js代码内有一个是改变某个DOM元素样式的代码,执行了之后只是记录下这个渲染事件,不会去切换渲染线程进行渲染,而是继续执行剩下的主栈列内的代码,好烦..发现又要解析主栈列和任务队列的概念..可以去看阮一峰的event loop解析,就是说,算了上代码吧:

    $.ajax({   
    type:'get',   
    url:url,  
    beforeSend:function() {
          console.log('发送请求了,别看我在ajax内,其实跟它没什么关系')         
       },  
    success:function(data){      
          console.log('ajax执行完毕,我比setTimeout的事件优先级要高')            
       },  
    })
    setTimeout(function() {   
    console.log('定时器也完了')
    },0)
    console.log('我在主栈列,让我先走')
    //触发顺序
    1.发送请求了,别看我在ajax内,其实跟它没什么关系
    2.我在主栈列,让我先走
    3.jquery-1.9.1.min.js:5 XHR finished loading: GET "http://localhost:2000/123".
    4.ajax执行完毕
    5.定时器也完了
    

    js引擎在解析js代码的时候,遇到settimeout和setInterval或者ajax都会先告诉它们缓缓,你们先进任务队列里面等等,我执行完剩下在主栈列内的代码先。

    然后执行完主栈列的代码之后,js线程完事之后,并不会马上去任务队列内找任务放到主栈列,而是..先查找刚刚是不是有需要渲染引擎要干的是..比如说你要改某个DOM元素的背景色,如果有的话,那么就会切换渲染线程,先把页面的渲染需要的repaint和reflow做了,关于repaint和reflow在这里不做陈述,有兴趣google一下吧。

    那让渲染引擎做完了渲染工作,浏览器才回去查找任务队列有没有人挂号,采取的是轮询机制,跟医生看病人差不多,就是说一个一个来,随便说一句ajax比settimeout和setInterval优先级要高的,比如说执行完ajax事件1,就回去看任务队列?nonono,先看有没有渲染引擎要做的事,就是说再走一次刚刚主栈列的流程,没有渲染的事了?那就下一位病人吧。

    回到主题...为什么我们需要异步,因为刚刚前文所说的js阻塞,如果说ajax是同步执行的..那么就会等服务器响应我的请求,拿到数据再做其他事情,那如果服务器不行请求很久那岂不是很low,那么浏览器干了什么就是在走到ajax的时候,在把它推到任务队列之前,起一个http线程,去发送请求,请求完成了,再讲ajax事件推到任务队列的末端,从而实现异步,在说一句就是根据上面所说的其实settimeout和setInterval要比预期的事件要多一点的,因为在队列中,不是即刻执行,明天再更新。

    好吧,干货来了,在日常的写(lu)作(ma)中我们应该怎么样优(zuo)雅(si)地利用异步机制去完成我们想要的异步操作呢:

    (一)welcome to callback hell(回调函数)

    function getSomething(fn){
       var num=0;
       settimeout(function(){
           num=1;
           fn(num);
       })
    }
    function compute(x) {
       alert(x * 2);
    }
    getSomething(compute);//任性,不喜欢大小写命名法
    

    如上文所说,settimeout内的js代码都进入了主栈列,那么执行顺序就是从上至下了,但是在复杂的需求下这种方法会产生callback hell,并且还不容易看出详细异步步骤,不简单的逻辑的话可以用用。

    (二)promise

    function getSomething() { 
        var r = 0; 
        return new Promise(function(resolve) { 
            setTimeout(function() { 
                r = 2; 
                resolve(r); 
            }, 10); 
        });}
    function compute(x) { 
        alert(x * 2);
    }
    getSomething().then(compute);
    //没有接触Promise的朋友可以去看看Promise的使用,因为一时半会又讲不完...本文仅提供异步方法
    

    (三)generator

    function getSomething() {   
        var r = 0;   
        setTimeout(function() {      
            r = 2;      
            it.next(r);   
        }, 10);
    }
    function *compute(it) {   
        var x = yield getSomething();   
        alert(x * 2);
    }
    var it = compute();
    it.next();
    //我只负责提供demo......详细可以去看es6的教程
    

    (四)promise + generator

    function getSomething() {   
        var r = 0;   
        return new Promise(function(resolve) {      
        setTimeout(function() {         
            r = 2;         
            resolve(r);      
        }, 10);   
     });
    }
    function *compute() {   
        var x = yield getSomething();   
        alert(x * 2);
    }
    var it = compute();it.next().value.then(function(value) {   
        it.next(value);
    });
    

    (五)async (ES6都玩腻了,ES7还远吗,异步操作终极大法)

    function getSomething() { 
        var r = 0; 
        return new Promise(function(resolve) { 
            setTimeout(function() { 
            r = 2; 
            resolve(r); 
        }, 10); 
    });}
    async function compute() { 
        var x = await getSomething(); 
        alert(x * 2);
    }
    compute();
    

    困死本宝宝了..1点了。

    好咯,晚安,world peace.

    相关文章

      网友评论

          本文标题:初步浅析浏览器异步机制

          本文链接:https://www.haomeiwen.com/subject/quelbttx.html