最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 大前端进击之路(二)|JavaScript异步编程

    正文概述 掘金(跟兔虫)   2021-01-04   382

    经典面试题

    我们先来看一道经典的面试题,让我们的小脑袋瓜子思考起来~如果你对这道题有清晰的思路并且了解背后的原因,那么请直接点赞评论加关注!!!!!

    //请写出输出内容
    async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
    async function async2() {
    	console.log('async2');
    }
    
    console.log('script start');
    
    setTimeout(function() {
        console.log('setTimeout');
    }, 0)
    
    async1();
    
    new Promise(function(resolve) {
        console.log('promise1');
        resolve();
    }).then(function() {
        console.log('promise2');
    });
    console.log('script end');
    

    答案!你答对了吗?没对的不要跑,睁大你的小眼睛仔细看以下的内容大前端进击之路(二)|JavaScript异步编程

    /*
    script start
    async1 start
    async2
    promise1
    script end
    async1 end
    promise2
    setTimeout
    */
    

    JS采用单线程模式工作的原因

    为了回答这个问题我们首先需要知道JS的执行环境是单线程的,是因为JS语言最早是运行在浏览器端的语言,目的是为了实现页面上的动态交互。实现动态交互的核心就是DOM操作,因此决定了JS必须是单线程模式工作。我们来假设一下如果JS是多线程一起工作的,其中一个线程修改了一个DOM元素,另外的一个线程同时又要删除这个DOM元素,那么此时浏览器就懵逼了,无法明确以哪个工作线程为准。所以为了避免线程同步的问题,JS就被设计成了单线程的工作模式。

    单线程的优势和弊端

    采用单线程的工作模式可以节省内存,节约上下文切换时间,没有锁的问题。但弊端也很明显,如果中间有一个任务需要花费大量的时间,那么后面的任务就需要等待这个任务完成后才能执行,就会出现假死的情况,对用户很不友好。为了解决这个问题JS给出了两种执行模式:同步模式(Synchronous)和异步模式(Asynchronous)

    同步模式和异步模式

    同步模式

    同步模式其实很好理解,举个栗子:

    在这里其实我们已经能够看出来问题,我们必须等到水烧开后才去准备要煮的材料。回到概念里就是在同步模式下我们的代码是依次执行,后一个任务必须等待前一个任务结束才能开始执行。程序执行的顺序和代码编写的顺序是完全一致的。在单线程模式下,大多数任务都是以同步模式执行。

    异步模式

    我们在烧水的过程中去干了别的事情,就属于异步模式,异步模式中不会等待异步任务的结束才开始执行下一个同步的任务,都是开启过后就立即执行下一个任务。

    EventLoop事件循环和消息队列

    • EventLoop是一种循环机制,主线程从消息队列中读取任务并按照顺序执行,这个过程是循环不间断的。
    • 消息队列是存放异步任务的地方,当我们的同步任务都执行完毕后,EventLoop会从消息队列中依次取出异步任务放到调用栈中进行执行。

    宏任务和微任务

    • 宏任务可以理解为每次执行栈执行的代码就是一个宏任务

    • 微任务可以理解为每个宏任务执行结束后立即执行的任务,发生在宏任务后,渲染之前,执行微任务。

    大前端进击之路(二)|JavaScript异步编程 大前端进击之路(二)|JavaScript异步编程

    异步编程方案的本质—回调函数

    回调函数:由调用者定制,交给执行者执行的函数。

    我们通过 callback 回调函数、事件发布/订阅、Promise 等来组织代码,本质都是通过回调函数来实现异步代码的存放与执行。

    // callback就是回调函数
    // 就是把函数作为参数传递,缺点是不利于阅读,执行顺序混乱。
    function foo(callback) {
        setTimeout(function(){
            callback()
        }, 3000)
    }
    
    foo(function() {
        console.log('这是回调函数')
        console.log('调用者定义这个函数,执行者执行这个函数')
        console.log('其实就是调用者告诉执行者异步任务结束后应该做什么')
    })
    

    更优异步编程统一方案——Promise

    Promise概述

    Promise概念MDN传送门

    // 我们想要执行完第一个再执行第二个再执行第三个
    // 虽然我们使用同步的方式将异步的代码学出来了,但是这样的回调是不是让我们的小脑袋瓜子嗡嗡的?
    setTimeout(() => {
        console.log('执行第一个');
        setTimeout(() => {
            console.log('执行第二个');
            setTimeout(() => {
                console.log('执行第三个');
                setTimeout(() => {
                    console.log('执行第四个');
                    setTimeout(() => {
                        console.log('执行第五个');
                    }, 2000);
                }, 2000);
            }, 2000);
        }, 2000);
    }, 2000);
    

    Promise基本用法

    // Promise 基本示例
    // promise的英文意思是承诺
    // 在JS中Promise是一个对象,接收一个函数作为参数
    const promise = new Promise(function (resolve, reject) {
      // 这里用于“兑现”承诺
      // resolve(100) // 承诺达成
      reject(new Error('promise rejected')) // 承诺失败
    })
    
    promise.then(function (value) {
      // 即便没有异步操作,then 方法中传入的回调仍然会被放入队列,等待下一轮执行
      console.log('resolved', value)
    }, function (error) {
      console.log('rejected', error)
    })
    

    Promise案例

    我们用Promise来封装一个AJax

    function ajax (url) {
      return new Promise((resolve, rejects) => {
        // 创建一个XMLHttpRequest对象去发送一个请求
        const xhr = new XMLHttpRequest()
        // 先设置一下xhr对象的请求方式是GET,请求的地址就是参数传递的url
        xhr.open('GET', url)
        // 设置返回的类型是json,是HTML5的新特性
        // 我们在请求之后拿到的是json对象,而不是字符串
        xhr.responseType = 'json'
        // html5中提供的新事件,请求完成之后(readyState为4)才会执行
        xhr.onload = () => {
          if(this.status === 200) {
            // 请求成功将请求结果返回
            resolve(this.response)
          } else {
            // 请求失败,创建一个错误对象,返回错误文本
            rejects(new Error(this.statusText))
          }
        }
        // 开始执行异步请求
        xhr.send()
      })
    }
    
    ajax('/api/user.json').then((res) => {
      console.log(res)
    }, (error) => {
      console.log(error)
    })
    

    Promise的链式调用

    误区

    • 嵌套使用的方式是使用Promise最常见的误区。我们要使用promise的链式调用的方法尽可能保证异步任务的扁平化。
    // 嵌套使用 Promise 是最常见的误区
    ajax('/api/urls.json').then(function (urls) {
      ajax(urls.users).then(function (users) {
        ajax(urls.users).then(function (users) {
          ajax(urls.users).then(function (users) {
            ajax(urls.users).then(function (users) {
            })
          })
        })
      })
    })
    

    链式调用的理解

    • promise对象then方法,返回了全新的promise对象。可以再继续调用then方法,如果return的不是promise对象,而是一个值,那么这个值会作为resolve的值传递,如果没有值,默认是undefined
    • 后面的then方法就是在为上一个then返回的Promise注册回调
    • 前面then方法中回调函数的返回值会作为后面then方法回调的参数
    • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束

    Promise的异常处理

    • then中回调的onRejected方法
    • .catch()
    ajax('/api/user.json')
      .then(function onFulfilled(res) {
        console.log('onFulfilled', res)
      })
      .catch(function onRejected(error) {
        console.log('onRejected', error)
      })
      
    // 相当于
    ajax('/api/user.json')
      .then(function onFulfilled(res) {
        console.log('onFulfilled', res)
      })
      .then(undefined, function onRejected(error) {
        console.log('onRejected', error)
      })
    

    参考


    起源地下载网 » 大前端进击之路(二)|JavaScript异步编程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元