美文网首页
JS-异步和同步

JS-异步和同步

作者: 小废柴JH | 来源:发表于2019-08-18 16:30 被阅读0次

    简单来说同步和异步可以这么形容。
    同步:等待结果
    异步:不等待结果
    需要注意的是异步常常伴随回调一起出现,但是异步不是回调,回调也不一定是异步。
    同步的 sleep:

    function sleep(seconds){
        var start = new Date()
        while(new Date() - start < seconds * 1000){
              
        }
        return
    }
    console.log(1)
    sleep(3)
    console.log('wake up')
    console.log(2)
     // 打印顺序是 1, wake up, 2
    

    js在这一段时间内,会一直去查看时间到了没有,时间到了再去执行相应的代码,也就是说js会一直等下去,等待的过程不做任何事情,就是去反复的查看时间到了没有。

    异步的 sleep:

    function sleep(seconds, fn){
        setTimeout(fn, seconds * 1000)
    }
    console.log(1)
    sleep(3, ()=> console.log('wake up'))
    console.log(2)
    // 打印顺序是 1, 2, wake up
    

    根据上面的代码可以看出,js在执行代码的时候是不会等待异步代码的结果,而是直接去执行了下面的代码。那么js看到异步代码会做什么昵?其实很简单,就是告诉浏览器,我这有个异步代码,你帮我订个闹钟,时间到了通知我,我去调用一下。这也是为什么js是单线程,可效率很高的原因,因为有很多人帮它做事。

    异步的例子:
    获取图片的宽度,但是图片加载到页面时需要时间的,因此下面的代码获取到的图片宽度为0:

    document.getElementsByTagName('img')[0].width // 宽度为 0
    console.log('done')
    

    解决方法:img加载成功后就会触发onload,这样的话就可以在onload后可以获取到width了

    document.getElementsByTagName('img')[0].onload = function(){
        console.log(this.width) // 宽度不为 0
        console.log('real done')
    }
    console.log('done')
    

    AJAX 中的异步
    同步:

    let request = $.ajax({
      url: '.',
      async: false  // 会一直等待响应
    })
    console.log(request.responseText)
    

    异步:

    $.ajax({
        url: '/',
        async: true, 
        success: function(responseText){ // 执行完会来调用这个函数
            console.log(responseText)
        }
    })
    console.log('请求发送完毕')  // 请求完,不等响应,就执行本行代码
    

    两种方式可以获取异步的结果

    1. 轮询: 隔一段时间就去查看一下,看有没有结果。
    2. 回调
      回调的形式
      1.Node.js 的 error-first 形式
     fs.readFile('./1.txt', (error, content)=>{
         if(error){
             // 失败
         }else{
             // 成功
         }
     })
    
    1. jQuery 的 success / error 形式
     $.ajax({
             url:'/xxx',
             success:()=>{},
             error: ()=>{}
         })
    
    1. jQuery 的 done / fail / always 形式
    $.ajax({
            url:'/xxx',
         }).done( ()=>{} ).fail( ()=>{} ).always( ()=> {})
    
    1. Prosmise 的 then 形式
        $.ajax({
           url:'/xxx',
         }).then( ()=>{}, ()=>{} ).then( ()=>{})
    

    promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。使用回调来获取异步结果,而获取可能成功或者失败,因此不同的人就产生了如上不同的写法,多种写法不够统一,因此就出现了promise规范,promise就是来解决获取结果成功或者失败的命名规范和形式,then(成功函数,失败函数),成功函数和失败函数里面是获取到结果后所做的动作,如 then(成功函数,失败函数)。promise是对函数回调形式的一种规范。
    在promise/A+规范中,如链式then里面的第一个then不管是成功函数和失败函数的顺利执行,都会去执行第二个then里面的成功函数,以此类推。但是第一个then里面不管是成功函数和失败函数出现了异常,那么会有第二个then里面的失败函数来接住这个异常。而catch也是捕获异常的方法,通常用来兜底的。相当于then的一个语法糖,也就是第一个(成功)参数传undefined,then(undefined,失败函数)。

    自己返回 Promise

    function ajax(){
        return new Promise((resolve, reject)=>{
            做事
            如果成功就调用 resolve
            如果失败就调用 reject
        })
    }
    var promise = ajax()
    promise.then(successFn, errorFn)
    

    async / await
    把异步代码变成同步代码,也就是用同步的形式写异步代码。await后面跟的是一个会返回promise的函数。一个函数里面有await,那么外面最好写一个async,不然会报错。

    实现一个简单的Promise
    满足以下需求:

    function Promise(???){
        ???
        return ???
    }
    
    var promise = new Promise(function(x,y){
        setTimeout(()=>{
            x(101)
        }, 3000)
    })
    promise.then((z)=>{
        console.log(z)  // 101
    })
    

    分析:
    首先搞清楚输入和输出是什么!!!涉及到传参为函数的话,要考虑到函数的调用,没有this的话,就把call的第一个参数设为undefined。而Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。通常我们把pending变为fulfilled的过程称为resolved,把pending变为rejected的过程称为rejected。
    代码

    function Promise(fn){
        var status = 'pending'   // 记录初始状态
        function successNotify(){
            status = 'resolved'
            toDoThen.apply(undefined, arguments)
        }
        function failNotify(){
            status = 'rejected'
            toDoThen.apply(undefined, arguments)
        }
        function toDoThen(){   
            setTimeout(()=>{ // 保证回调是异步执行的
                if(status === 'resolved'){
                    for(let i =0; i< successArray.length;i ++)    {
                        successArray[i].apply(undefined, arguments)
                    }
                }else if(status === 'rejected'){
                    for(let i =0; i< failArray.length;i ++)    {
                        failArray[i].apply(undefined, arguments)
                    }
                }
            })
    
        }
        var successArray = []  // 创建成功队列
        var failArray = []  // 创建失败队列
        fn.call(undefined, successNotify, failNotify)
        return {
            then: function(successFn, failFn){
                successArray.push(successFn) // 把成功函数放进成功队列里面
                failArray.push(failFn) // 把失败函数放进失败队列里面
                return undefined // 简化, 链式then的话可继续返回then
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:JS-异步和同步

          本文链接:https://www.haomeiwen.com/subject/erwrsctx.html