JS异步

  • 单线程

    JS是单线程,一次只能做一件事,如果同一时间有多个任务的话,这些任务需排队,前一个任务执行完才会执行后一个任务。

    JS为什么是单线程,这与JS用途有很大关系,JS是浏览器脚本语言,主要用来实现与用户交互,利用JS可以实现对DOM的各种操作,如果是多线程会带来很复杂的同步问题

  • 为什么需要异步

    JS 为单线程同一时间只能处理同个任务,但如果前一个任务执行时间很长,如文件读取和 ajax 操作,后一个任务就不得不等着,严重影响用户体验。JS 的异步就是先挂起处于等待中的任务,先运行排在后面的任务,等到文件读取或 ajax 有了结果后再回头执行挂起的任务

    异步任务指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,如图片、音乐的加载。

  • 异步机制

    异步如何实现,回调和事件循环。

    任务队列:异步任务不会进入主线程,而是先进入任务队列,任务队列是一个先进先出的数据结构,一个异步任务结束就会在任务队列中添加事件,即可以进入执行栈。但此时的主线程不一定有空,当主线程处理完其他任务队列有空时,就会读取任务队列,读取里面有哪些事件,前面的事件会被优先处理,如果该任务指定了回调函数,就会执行回调函数中的代码。

    单线程从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中的读取新的任务,这就叫做任务循环,因每个任务都由一个事件触发,因此也叫事件循环。

    JS异步机制步骤

    1. 所有同步任务都在主线程上执行,形成执行栈
    2. 主线程外,还存在一个任务队里,只有异步任务有了结果,就会在任务队列中放置一个事件
    3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件,对应的异步任务结束等待状态,进入执行栈,开始执行。
    4. 主线程不断重复第三步
  • 异步编程

    • 回调函数

      一个函数(回调函数)作为参数传递给另一个函数,并在函数中被调用

      使用 ajax 时,我们就用到了回调函数实现的异步

      var req = new XMLHttpRequest()
      req.open("GET",url)
      req.send(null)		//异步任务
      req.Onreadystatechange = function(){}	//事件回调,得到相应之后触发该事件
      

      还要像 setTimeout

      回调函数容易形成回调炼狱,不利于代码阅读

    • Promise

      ES6.0 新增的异步对象

      • Promise 是一个构造函数,既然是构造函数,那么我们就可以 new Promise() 得到一个 Promise 实例

      • 在 Promise 上,有两个函数,分别叫做 resolve (成功之后的回调函数) 和 reject (失败之后的回调函数)

      • 在 Promise 构造函数的 Prototype 属性上,有一个 .then() 方法,也就是说,只要是 Promise 函数构造创建的实例,都可以访问到 .then方法

      • Promise 表示一个异步操作,当我们 new Promise 实例,这个实例就表示一个具体的异步操作

      • 既然 Promise 创建的实例是一个异步操作,那么这个异步操作的结果,只能有两种状态:

        1. 状态1:异步执行成功了,需要在内部调用成功的回调函数 resolve 把结果返回给调用者

        2. 状态2:异步执行失败了,需要在内部调用失败的回调函数 reject 把结果返回给调用者

        3. 由于 Promise 实例是一个异步操作,所以内部拿到操作的结果后,无法使用 return 把操作的结果返回个调用者;这时候,只能使用回调函数的形式,来把成功或失败的结果,返回给调用者

      • 们可以在 new 出来的 Promise 实例上调用.then() 方法,预先为这个 Promise 异步操作,指定成功和失败的回调函数

    • 用 Promise 封装读取文件操作

      function getFileByPath(fpath){
          return new Promise(function (resolve,reject) {
              fs.readFile(fpath, 'utf-8', (err,dataStr) => {
                  if(err) return reject(err)
                  resolve(dataStr)
              })
          })
      }
      getFileByPath('./11.txt').then(function(data){
          console.log(data+'访问成功')
      },function (err) {
          console.log(err.message+'访问失败')
      })
      
原文地址:https://www.cnblogs.com/angle-yan/p/13365745.html