zoukankan      html  css  js  c++  java
  • 浅谈JS异步轮询和单线程机制

    单线程特点执行异步操作 

      js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务就会排队形成一个任务队列排队等候执行.一般而已,相对耗时的操作是要通过异步来进行加载,可以避免导致页面的假死.
    setTimeout(function(){
         console.log(这是timeout事件回调);
    },1000);
      JS阻塞renderdom的渲染,同一时间只能做一件事,避免了浏览器渲染DOM冲突,JS执行的时候,JS可以修改DOM,浏览器DOM渲染会停止,WebWorker支持多线程,但不能渲染DOM.

    解决方案——异步

    setTimeout(function(){
         console.log(这是timeout事件回调);
    },1000);
      执行这段代码的时候,浏览器异步执行计时操作,传入setTimeout的函数会被暂存起来,当1000ms到了后,会触发定时事件,这个时候,就会把回调函数放到任务队列里,待所有程序执行完,处于空闲的状态时,会立马看看有没有暂存起来要执行的任务,整个程序就是通过这样的一个个事件驱动起来的,如下图1.1所示:
    图1.1 工作原理图
      "任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),例如onClick事件,只要指定这些事件的异步操作,就会进入任务队列中等待执行.
      其中JS实现异步是不断通过事件轮询(Event Loop)的方式实现的,同步代码直接执行,异步代码先放在异步队列中,等待同步代码执行完,轮询执行异步队列中的异步代码
      AJAX请求天气接口数据如下:
    <script type="application/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="application/javascript">
        function urlencode (str) {
            str = (str + '').toString();
            return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/(/g, '%28').
            replace(/)/g, '%29').replace(/*/g, '%2A').replace(/%20/g, '+');
        }
       var city= '深圳',$citycode=urlencode(city);
       var url='http://v.juhe.cn/weather/index?format=2&cityname='+$citycode+'&key=c82727e986a4f6cfc6ba1984f1f9183a';
        $.ajax({url: url,
            dataType: "jsonp",
            type:"get",
            data:{location:city},
            success:function(data) {
                var sk = data.result.sk;
                var today = data.result.today;
                var futur = data.result.future;
                var fut = "日期温度天气风向";
                $('#mufeng').html(
                    "<p>" + '当前: ' + sk.temp + '℃ , ' + sk.wind_direction + sk.wind_strength +
                    ' , ' + '空气湿度' + sk.humidity + ' , 更新时间' + sk.time +
                    "</p><p style='padding-bottom: 10px;'>" + today.city + ' 今天是: ' + today.date_y +
                    ' ' + today.week + ' , ' + today.temperature + ' , ' + today.weather + ' , ' + today.wind + "<p></p>"
                );
            }});
    
    </script>

    结果如下所示:先打印cc1,cc222, 然后执行25行success中代码

    问题

    1. Callback没有按照我们预期的顺序执行
    2. Callback不易于我们进行模块化管理

    jQuery.Deferred

    jQuery1.5的变化,语法糖改变,遵循开发封闭原则

    $.ajax({url: url,
            dataType: "jsonp",
            type:"get",
            data:{location:city}})
            .done(function(data){
                if(data.result){
                    var sk = data.result.sk;
                    var today = data.result.today;
                    var futur = data.result.future;
                    var fut = "日期温度天气风向";
                    $('#mufeng').html(
                        "<p>" + '当前: ' + sk.temp + '℃ , ' + sk.wind_direction + sk.wind_strength +
                        ' , ' + '空气湿度' + sk.humidity + ' , 更新时间' + sk.time +
                        "</p><p style='padding-bottom: 10px;'>" + today.city + ' 今天是: ' + today.date_y +
                        ' ' + today.week + ' , ' + today.temperature + ' , ' + today.weather + ' , ' + today.wind + "<p></p>"
                    );
                }else {
                    console.log('该接口调用达到上限')
                }
            })
            .fail(function(){
                console.log("获取数据失败")
            })
            .done(function(data){
                console.log(data)
            })

    Deferred的另一种写法:

    $.ajax({url: url,
            dataType: "jsonp",
            type:"get",
            data:{location:city}})
            .then(function(data){
                if(data.result){
                    var sk = data.result.sk;
                    var today = data.result.today;
                    var futur = data.result.future;
                    var fut = "日期温度天气风向";
                    $('#mufeng').html(
                        "<p>" + '当前: ' + sk.temp + '℃ , ' + sk.wind_direction + sk.wind_strength +
                        ' , ' + '空气湿度' + sk.humidity + ' , 更新时间' + sk.time +
                        "</p><p style='padding-bottom: 10px;'>" + today.city + ' 今天是: ' + today.date_y +
                        ' ' + today.week + ' , ' + today.temperature + ' , ' + today.weather + ' , ' + today.wind + "<p></p>"
                    );
                }else {
                    console.log('该接口调用达到上限')
                }
            },function(){
                console.log("获取数据失败1")
            })
            .then(function(data){
                console.log(data);
            },function(){
                console.log("获取数据失败2")
            })

    执行结果如下图所示:

     

     $.Defferred 对象封装 返回一个defferred对象

        function waitHandleWeather() {
            var dtd = $.Deferred()
            var wait =function(dtd){
                $.ajax({url: url,
                    dataType: "jsonp",
                    type:"get",
                    data:{location:city}})
                    .then(function(data){
                        dtd.resolve(data)
                    },function(){
                        dtd.reject('该接口调用达到上限') //返回promise对象,如果返回dtd,外面就可以修改dtd的操作,不安全
                    });
                return dtd.promise();
            }
            return wait(dtd); //返回promise对象
        }
        var weatherDataDeferred = waitHandleWeather();
        $.when(weatherDataDeferred).then(function(data){
            if(data.result){
                var sk = data.result.sk;
                var today = data.result.today;
                var futur = data.result.future;
                var fut = "日期温度天气风向";
                $('#mufeng').html(
                    "<p>" + '当前: ' + sk.temp + '℃ , ' + sk.wind_direction + sk.wind_strength +
                    ' , ' + '空气湿度' + sk.humidity + ' , 更新时间' + sk.time +
                    "</p><p style='padding-bottom: 10px;'>" + today.city + ' 今天是: ' + today.date_y +
                    ' ' + today.week + ' , ' + today.temperature + ' , ' + today.weather + ' , ' + today.wind + "<p></p>"
                );
            }else {
                console.log('该接口调用达到上限')
            }
        },function(err){
            console.log(err)
        });

    同步和异步的区别

      同步在执行的过程会阻塞I/O,在正常的流程中执行的顺序不同,例如setTimeout、setInterval,会改变流程执行的顺序,尽管setTimeout的time延迟时间为0,其中的function也会被放入一个队列中,等待下一个机会执行,当前的代码(指不需要加入队列中的程序)必须在该队列的程序完成之前完成,因此结果可能不与预期结果相同。因此,异步能改变流程执行的顺序,同步不会改变流程执行的顺序,依次执行.
     

    jQuery.Deferred和Promise 区别

    Promise不能主动干预改变promise的结果,Deffrred可以去改变干预执行的结果

    最后,如果想看promise相关内容,请移步https://www.cnblogs.com/fuGuy/p/9215884.html

  • 相关阅读:
    js array数组检测方式
    js 获取时间戳
    接收二进制流(ArrayBuffer) ,并且显示二进制流图片
    文字小于12px时,设置line-height不居中问题
    设置文字小于12px
    Kafuka面试(整合Kafka两种模式区别)
    secondary namenode 检查点
    MapReduce总结
    Map、Reduce和Job方法总结
    Hadoop 两种环境下的checkpoint机制
  • 原文地址:https://www.cnblogs.com/fuGuy/p/9208379.html
Copyright © 2011-2022 走看看