• 技术文章 >web前端 >js教程

    手把手带你弄懂JavaScript中的异步编程

    青灯夜游青灯夜游2021-06-03 11:02:42转载100
    本篇文章带大家了解JavaScript中的异步编程。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

    异步,就是非同步....

    这节内容可能会有点枯燥,但是却是 JavaScript 中非常重要的概念,非常有必要去学习。

    目的

    引子问题

    $.ajax({
      url: "www.xx.com/api",
      async: false, // true
      success: function(result) {
        console.log(result);
      },
    });
    // 异步批量更新DOM(vue-nextTick)
    // <p id="app">{{num}}</p>
    new Vue({
      el: "#app",
      data: {
        num: 0,
      },
      mounted() {
        let dom = document.getElementById("app");
        while (this.num !== 100) {
          this.num++;
        }
        console.log("Vue num=" + this.num, "DOM num=" + dom.innerHTML);
        // Vue num=100,DOM num=0
        // nextTick or setTimeout
      },
    });

    产生异步的原因

    原因:单线程(一个时间点,只做一件事),浏览器的 JS 引擎是单线程导致的。

    单线程是指在 JS 引擎中负责解释和执行 IavaScript 代码的线程只有一个,不妨叫它主线程。

    所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成再执行后面一个任务。

    先看看一下浏览器内核的线程图:

    1.jpg

    其中,渲染线程和 JS 线程互斥

    假设有两个函数,一个修改一个删除,同时操作一个 DOM 节点,假如有多个线程的话,两个线程一起执行,肯定就死锁了,就会有问题。

    为什么 JS 要设计为单线程,因为浏览器的特殊环境。

    单线程的优缺点:

    这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

    常见的堵塞(死循环):

    while (true) {}

    JS 在设计之初就以运行在浏览器中的脚本语言,所以也不想搞得这么复杂,就设计成了单线程,也就是,一个时间点,只能做一件事。

    为了解决单线程堵塞这个缺点:产生了异步。

    拿吃泡面举例:

    看电视就是异步操作,热水壶响,就是回调函数。

    异步编程

    JS 中大多的代码都是同步执行的,只有极个别的函数是异步执行的,异步执行的代码,则需要异步编程。

    异步代码

    setTimeout(() => {
      console.log("log2");
    }, 0);
    console.log("log1");
    // ?? log1 log2

    异步代码的特点:不是立即执行,而是需要等待,在未来的某一个时间点执行。

    同步代码异步代码
    <script>代码网络请求(Ajax)
    I/O 操作定时器(setTimeout、setInterval)
    渲染操作Promise(then)

    async/await

    回调函数

    异步代码最常见的写法就是使用回调函数。

    // 注意到click方法中是一个函数而不是一个变量
    // 它就是回调函数
    $("#btn_1").click(function() {
      alert("Btn 1 Clicked");
    });
    // 或者
    function click() {
      // 它就是回调函数
      alert("Btn 1 Clicked");
    }
    $("#btn_1").click(click);

    回调函数的缺点也很明显,容易产生回调地狱:

    2.png

    异步编程的三种方式

    function getOneNews() {
      $.ajax({
        url: topicsUrl,
        success: function(res) {
          let id = res.data[0].id;
          $.ajax({
            url: topicOneUrl + id,
            success: function(ress) {
              console.log(ress);
              render(ress.data);
            },
          });
        },
      });
    }
    function getOneNews() {
      axios
        .get(topicsUrl)
        .then(function(response) {
          let id = response.data.data[0].id;
          return axios.get(topicOneUrl + id);
        })
        .then((res) => {
          render(res.data.data);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
    async function getOneNews() {
      let listData = await axios.get(topicsUrl);
      let id = listData.data.data[0].id;
      let data = await axios.get(topicOneUrl + id);
      render(data.data.data);
    }

    在线预览

    预览地址:http://jsrun.net/s43Kp/embedded/all/light

    问题??

    如果多个异步代码同时存在,那么执行顺序应该是怎样的?那个先执行、那个后执行了?

    宏任务和微任务

    异步代码的划分,异步代码分宏任务和微任务。

    宏任务(不着急)微任务(着急)
    <script>整体代码Promise
    setTimeout/setInterval

    事件循环(Event loop)

    3.png

    执行顺序:

    重复从宏任务和微任务队列里拿出任务去执行。

    总结

    因为浏览器设计的原因,JS 线程和渲染线程互斥,所以 JS 线程被设计成了单线程。

    因为单线程执行一些操作(如网络请求)时有堵塞的问题,所有产生了异步。

    因为有了异步,所以产生了异步编程,从而有了回调函数。

    因为回调函数写多了会产生回调地狱,所有又有了解决回调地狱的 Promise 写法

    自 ES7 标准后有了比 Promise 更加优雅的写法 ———— async/await 写法,也是异步编程的最终解决方法。

    因为 JS 的代码分为同步和异步代码,同步代码的执行顺序不必多说,自上而下的执行。

    但是如果有多个异步的代码,他的执行顺序又是怎么的呢??

    为了解决多个异步代码的执行顺序问了,有了事件循环(EventLoop),将异步任务区分为宏任务、微任务,依据规则依次执行。

    至此 完!

    练习

    console.log("script start");
    setTimeout(function() {
      console.log("timeout1");
    }, 10);
    new Promise((resolve) => {
      console.log("promise1");
      resolve();
      setTimeout(() => console.log("timeout2"), 10);
    }).then(function() {
      console.log("then1");
    });
    console.log("script end");

    写出 log 的输出结果,并说出理由。

    更多编程相关知识,请访问:编程视频!!

    以上就是手把手带你弄懂JavaScript中的异步编程的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:segmentfault,如有侵犯,请联系admin@php.cn删除
    专题推荐:javascript 异步编程
    上一篇:深入了解TypeScript中的5种设计模式 下一篇:一文了解JavaScript中合并和克隆对象的方法
    第16期线上培训班

    相关文章推荐

    • JavaScript中解析parseInt()的怪异行为• 聊聊JavaScript中eval()函数的用法• 浅谈JavaScript中的事件委托• JavaScript中如何更好地使用数组• 深入解析JavaScript中的作用域

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网