美文网首页
async+await优雅处理异步

async+await优雅处理异步

作者: noyanse | 来源:发表于2018-08-04 23:12 被阅读0次

    同步与异步

    1.同步

    一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」。

    /* 例2.1 */
    var x = true;
    while(x);
    console.log("don't carry out");    //不会执行
    

    2.js的单线程与异步

    我们知道,js的执行环境是「单线程」
    说到js的单线程(single threaded)和异步(asynchronous),很多同学不禁会想,这不是自相矛盾么?其实,单线程和异步确实不能同时成为一个语言的特性。js选择了成为单线程的语言,所以它本身不可能是异步的,但js的宿主环境(比如浏览器,Node)是多线程的,宿主环境通过某种方式(事件驱动,下文会讲)使得js具备了异步的属性。

    3.浏览器为耗时的任务开辟另外的线程

    js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行,但前端的某些任务是非常耗时的,比如http网络请求定时器事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。所以,浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程,浏览器定时触发器,浏览器事件触发线程,这些任务是异步的。

    4.任务队列

    刚才说到浏览器为网络请求这样的异步任务单独开了一个线程,那么问题来了,这些异步任务完成后,主线程怎么知道呢?答案就是回调函数,整个程序是事件驱动的,每个事件都会绑定相应的回调函数,举个栗子,有段代码设置了一个定时器

    setTimeout(function(){
        console.log(time is out);
    },50);
    

    执行这段代码的时候,浏览器异步执行计时操作,当50ms到了后,会触发定时事件,这个时候,就会把回调函数放到任务队列里。整个程序就是通过这样的一个个事件驱动起来的。
    所以说,js是一直是单线程的,浏览器才是实现异步的那个

    要实现按顺序打印

    function ajax(word) {
        setTimeout(() => {
            console.log(word)
        },1000) 
    }
    ajax('1')
    console.log('2')
    

    上面这段代码,打印出2,1,因为setTimeout是异步,js遇到异步会先挂起,先执行同步任务。

    1.用回调的方法解决

    function ajax1(word,fn) {
        setTimeout(() => {
            console.log(word)
            fn()
        },1000)
    }
    ajax1('1',() => {
        ajax1('2',() => {
            ajax1('3',() => {
                ajax1('4',() => {
            
                })
            })
        })
    })
    

    如果项目复杂,就会有请求1,请求2,这就是传说中的回调地狱,简称callback hell

    2.promise解决方案

    function delay(word) {
        return new Promise((resolve,reject) => {
            setTimeout(() => {
                resolve(word)
            },2000)
        })
    }
    
    delay('孙悟空')
        .then((word) => {
            console.log(word)
            return delay('猪八戒')
        })
        .then(word => {
            console.log(word)
            return delay('沙悟净')
        })
        .then(word => {
            console.log(word)
        })
    

    3.async+await

    function delay(word) {
        return new Promise((resolve,reject) => {
            setTimeout(() => {
                resolve(word)
            },2000)
        })
    }
    //async+await一定要一起使用,async定义函数,await在async内部使用,等待异步执行完毕
    async function start() {
        const word1 = await delay('孙悟空')
        console.log(word1)
        const word2 = await delay('猪八戒')
        console.log(word2)
        const word3 = await delay('沙悟净')
        console.log(word3)
    }
    start()
    

    下面用一个小球运动的例子来描述

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            .ball{
                width: 40px;height: 40px;border-radius: 20px;
            }
            .ball1{
                background: red;
            }
            .ball2{
                background: yellow;
            }
            .ball3{
                background: #ccc;
            }
        </style>
    </head>
    <body>
        <div class="ball ball1" style="margin-left:0"></div>
        <div class="ball ball2" style="margin-left:0"></div>
        <div class="ball ball3" style="margin-left:0"></div>
        <script type="text/javascript">
            var ball1 = document.querySelector('.ball1');
            var ball2 = document.querySelector('.ball2');
            var ball3 = document.querySelector('.ball3');
    
    //用回调的方法写动画
            function animate(ball,distance,cb){
                setTimeout(function(){
                    var marginLeft = parseInt(ball.style.marginLeft,10)
                    if(marginLeft === distance){
                        cb && cb()
                    }else{
                        if(marginLeft < distance){
                            marginLeft++
                        }else{
                            marginLeft--
                        }
                        ball.style.marginLeft = marginLeft + 'px'
                        animate(ball,distance,cb)
                    }
                },13)
            }
    
    
    //调用
            animate(ball1,100,function(){
                animate(ball2,200,function(){
                    animate(ball3,300,function(){
                        animate(ball3,150,function(){
                            animate(ball2,150,function(){
                                animate(ball1,150,function(){
                
                                })
                            })
                        })
                    })
                })
            })
    
    //----------------------------------------------------
    //promise方法写动画
            function promiseAnimate(ball,distance){
                return new Promise(function(resolve,reject){
                    function _animate(){
                        setTimeout(function(){
                            var marginLeft = parseInt(ball.style.marginLeft,10);
                            if(marginLeft === distance){
                                resolve();
                            }else{
                                if(marginLeft < distance){
                                    marginLeft++
                                }else{
                                    marginLeft--
                                }
                                ball.style.marginLeft=marginLeft + 'px'
                                _animate(ball,distance);
                            }
                        },13);
                    }
                    _animate();
                })
            }
    
    //调用
            promiseAnimate(ball1,100)
                .then(function(){
                    return promiseAnimate(ball2,200);
                })
                .then(function(){
                    return promiseAnimate(ball3,300);
                })
                .then(function(){
                    return promiseAnimate(ball3,150);
                })
                .then(function(){
                    return promiseAnimate(ball2,150);
                })
                .then(function(){
                    return promiseAnimate(ball1,150);
                })
    
    
    //async+await方法
    
            async function start() {
                await promiseAnimate(ball1,100)
                await promiseAnimate(ball2,200)
                await promiseAnimate(ball3,150)
                await promiseAnimate(ball2,150)
                await promiseAnimate(ball1,150)
            }
            start()
        </script>
    </body>
    </html>
    

    简单的ajax实现方法

    //--------------------回调-------------------------------------------------------------------------
    var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
    var result;
    
    var XHR = new XMLHttpRequest();
    XHR.open('GET', url, true);
    XHR.send();
    
    XHR.onreadystatechange = function() {
        if (XHR.readyState == 4 && XHR.status == 200) {
            result = XHR.response;
            console.log(result);
    
            // 伪代码
            var url2 = 'http:xxx.yyy.com/zzz?ddd=' + result.someParams;
            var XHR2 = new XMLHttpRequest();
            XHR2.open('GET', url, true);
            XHR2.send();
            XHR2.onreadystatechange = function() {
                //...
            }
        }
    }
    
    //---------promise----------------------------------------------------------------------------------------
    
    var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
    
    // Promise封装一个get请求的方法
    function getJSON(url) {
        return new Promise(function(resolve, reject) {
            var XHR = new XMLHttpRequest();
            XHR.open('GET', url, true);
            XHR.send();
    
            XHR.onreadystatechange = function() {
                if (XHR.readyState == 4) {
                    if (XHR.status == 200) {
                        try {
                            var response = JSON.parse(XHR.responseText);
                            resolve(response);
                        } catch (e) {
                            reject(e);
                        }
                    } else {
                        reject(new Error(XHR.statusText));
                    }
                }
            }
        })
    }
    
    getJSON(url).then(resp => console.log(resp));
    
    //-----------------------async------------------------------------------------------------------------
    
    function getUrl(url) {
        return new Promise((resolve,reject) => {
            let xhr = new XMLHttpRequest()
            xhr.open('GET',url,true)
            xhr.send()
            xhr.onreadystatechange = function() {
                if(xhr.readyState == 4){
                    if(xhr.status == 200) {
                        resolve(JSON.parse(xhr.response))
                    }else{
                        reject(new Error(XHR.statusText));
                    }
                }
            }
        }) 
    }
    
    async function start() {
        const word1 = await getUrl('https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10')
        console.log(word1)
    }
    start()
    

    相关文章

      网友评论

          本文标题:async+await优雅处理异步

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