• 浅谈js异步


    大家都知道,js是一个单线程的语言(只有一个线程来执行js函数),所以如果某一个函数执行任务耗时比较长的话,就会造成阻塞,使得后续任务一直处于等待状态。

    一、阻塞示例

            function f1(){
                for (var i = 0; i < 2000; i++) {
                        console.log('f1');
                }
            }
            function f2(){
                console.log('f2');
            }
            f1();
            f2();

    f1、f2依次执行,控制台打印:

    二、setTimeout函数

            function f1(){
                for (var i = 0; i < 2000; i++) {
                    setTimeout(()=>{
                        console.log('f1');
                    },500);
                }
            }
            function f2(){
                console.log('f2');
            }
            f1();
            f2();

    f1、f2依次执行,控制台打印:

    看上去好像先执行了f2,后续才执行了f1,其实不然,实际上依旧是先执行f1,再执行f2,没有实现异步,f1、f2依然是同步的(不要质疑,我说的是f1,f2没有实现异步)。

    首先执行f1,利用for循环开启2000个定时器;

    然后执行f2,打印字符串;

    时间到了,2000个定时器触发。

    注意:定时器到了时间触发之后,也并不是立即执行的,这要取决于js单线程内有没有还有没有函数正在运行,我们来看一个例子:

            function f8(){
                for (let i = 0; i < 2000; i++) {
                    setTimeout(()=>{
                        console.log('f8'+i);
                    },50);
                }
            }
            function f9(){
                for (let j = 0; j < 2000; j++) {
                        console.log('f9'+j);
                }
            }
            f8();
            f9();

    我们看到,定时器的时间参数值很小,50ms,依然是依次执行f8、f9;

    可以看到,虽然定时器先开启,并且第一个定时器在50ms之后,理当执行,但是此时发现,f9这个函数一直在执行任务,占据了js线程,所以这些定时器任务只好乖乖地等f9的循环走完,才开始执行。

    所以说js声明的所有变量/函数都是同步的(ES6的Promise实例化之后可以有一个立即执行代码块,可视为同步任务);

    但是我们可以通过各种方式开启一个异步任务(例如setTimeout函数的callback,Promise对象的then(callback)回调);

    三、同步队列、异步队列

    因为js是单线程的,所以任务会在线程上依次逐个执行;

    在主线程上的任务队列,这些任务是同步的,他们会按先后依次执行;

    另外还有一种任务队列,暂且称他们为异步任务队列,顾名思义,他们是异步任务,异步任务的特点是,必须等主线程上的任务没有了之后,才依次进入主线程执行。

    来个例子感受一下:

    ok,根据上图,我们可以知道,上述代码中,任务建立的顺序为:

    同步任务:Promise实例化、f1的第一行打印、f1的for循环开启1000个定时器、5个f2的字符串打印;

    异步任务:Promise的then回调、1000个定时器回调。

    再根据之前的任务执行顺序分析,先不要看下面的执行结果,在心中想一下控制台的打印结果。

    关于上述所提到的同步队列和异步队列(只是一种形象的说法),详情请戳下篇博客

    四、异步实现

    从上面我们可以发现,setTimeout(定时器)的回调是异步任务,这些个任务是直接放到异步任务队列中等待的。

    我们熟知的ajax之所以是异步,完全得益于XMLHttpRequest这个异步对象。

    ES6为方便异步编程,直接提供了一个异步对象Promise,使得异步编程变得简单。

  • 相关阅读:
    Linux查看CPU信息
    sed总结
    angularjs学习笔记--service、$http、$scope、angularjs指令、事件、api
    angularjs学习笔记--ng-model、controller、DI、$scope、$provide
    angularjs学习笔记--$http、数据渲染到表格、路由、依赖注入、provider
    angularjs学习笔记--主html&template html&module&template js、模块、控制器、双向数据绑定、过滤器
    angularjs学习笔记--视图、模板、组件、$http、$q、module
    angular学习笔记---下载并运行nicefish项目
    angular学习笔记---通过angular/cli建一个新的项目
    json模拟数据交互
  • 原文地址:https://www.cnblogs.com/eco-just/p/10389927.html
Copyright © 2020-2023  润新知