特皮技术团队:一年经验菜鸟前端眼中的异步编程

前端开发必不可少,什么是异步编程

  • 因为javascript语言是一门“单线程”的语言,因此,javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。javascript

  • 而做为前端开发,在面试与工做中相信你们必定被问过或常常须要用到异步编程,那么什么是异步编程呢?css

  • 一首歌,一篇文章 欢迎你关注公众号   html

首先咱们先区分一下什么是同步编程,什么是异步编程。

  • 同步编程:咱们都知道代码的执行顺序是自上而下执行的,那么同步就是须要每个任务都完成之后再去执行下一个任务,执行顺序与排列顺序是一致的。坏处,只要有一个任务耗时很长,后面任务都必须排队等着,常见的浏览器无响应,死循环。前端

  • 异步编程:每个任务有一个或多个回调函数,前一个任务执行完后,不是执行下一个任务,而是执行回调函数,后一个任务是不等前一个任务结束就执行的,因此程序的执行顺序与任务的排列顺序是不一致的。java

  • 简单的说咱们能够将异步编程理解为在约定的时间内完成的操做。node

  • 举个简单的例子:es6

    • 假设你设置了一个次日 7:00 的闹钟,那么咱们设置完,是一直在等待闹钟的提醒,再去作下一件事,仍是去作别的事情,相信你们都不会傻傻的在那等,在编程里这就异步编程。

异步编程怎么判断:是否阻塞 ? 同步阻塞 ,异步不阻塞。

  • 那么常见的异步编程有什么呢?
  • setTimeout
  • Ajax
  • Promise
  • async函数
  • 接下来咱们经过代码看看异步编程是如何执行的

定时器(setTimeOut)

  • 在规定的时间内完成操做:点击按钮,会打印“我先执行”  接着打印 “执行定时器”。能够看到虽然时间设置为0,可是定时器里的任务并非先被执行
<body>
    <button>点击触发定时器</button>
    <script>
        let btn = document.querySelector('button');
        btn.onclick = function () {
            setTimeout(function () {
                alert('执行定时器');
            }, 0)

        }
        console.log('我先执行');
    </script>
</body>

Ajax (异步JavaScript 和 XML)

  • 首先介绍咱们先一下Ajax。
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
  • Ajax是一种无需从新加载整个页面的状况下,可以更新部分网页的技术。web

  • 接着咱们经过一个简单的例子来看看ajax的强大(为了方便调用接口咱们直接使用网上连接https://cnodejs.org/api),为了观看效果明显一些会使用点击事件让你们看看触发结果面试

  • Ajax现代浏览器均支持XMLHTTPRequest对象,可是IE五、IE6须要兼容,下面就不作兼容处理了ajax

<body>
    <button onclick="loadXML()">点击获取结果</button>
    <div></div>
    <script>

        function loadXML() {
            let xmlhttp = new XMLHttpRequest();
            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    console.log(xmlhttp)
                    document.querySelector('div').innerHTML = JSON.parse(xmlhttp.responseText).data[0].content;
                }
            }
            xmlhttp.open('GET''https://cnodejs.org/api/v1/topics'true)
            xmlhttp.send()
            console.log('我先执行了')
        }
    </script>

</body>

  • 能够看获得结果依然是先打印了后面的“我先执行了”

Promise对象

  • 什么是promise对象 :

  • 从英文翻译来说就是”承诺“,既然是承诺确定就须要去完成嘛,因此仍是对应了上面说的 ,异步编程能够理解为在约定的时间内完成的操做。

  • promise有三种状态:pendding ,fulfilled,rejected

  • pendding:初始状态,不成功,不失败,
  • fulfilled:操做成功
  • rejected:操做失败
  • 当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;当promise状态一经改变,不会再变。

  • promise的使用

setTimeout(() => console.log(1), 0); // 异步
const p = new Promise((resolve, reject) => {
    console.log(2);                 // 同步
    setTimeout(() => {
        console.log(4)               // 异步优先级低于promise
    }, 0)
    resolve(3);
    console.log(5);                 // 同步
})
console.log(6)                      // 同步
p.then(value => {
    console.log(value);             // 异步
})

console.log(7)                      // 同步
  • 上面这一段代码其实在面试中很常见
  • 执行结果是  2 5 6 7 3 1 4
  • 再讲结果以前咱们应该了解一下es6的新增的任务队列 是在事件循环之上的(onclick, setTimeout,Ajax)
  • onclick 是浏览器内核的 DOM Binding 模块来处理的,当事件触发的时候,回调函数会当即添加到任务队列中。
  • setTimeout 是浏览器内核的 timer 模块进行的延时处理,当时间到达后才会回调添加到任务队列中。
  • Ajax 是浏览器内核 network 模块在网络请求完成以后,将回调添加到任务队列中。
  • 代码也写了,结果也看了,可是咱们为何要用promise呢?

  • 常见的回答都是解决回调地狱,其实promise也是用于解决异步编程的,

  • 在promise未出现前,咱们的异步编程都是经过纯回调解决的

  • 举个例子

// 纯回调
function createdAsync(value,success,catch){
    if (value){
        success()
    }else{
        catch()
    }
}
const success = function (){
    console.log('成功')
}
const catch = catch(){
    console.log('失败')
}

createdAsync(value,success,catch)


// promise 
const promise = createdAsync(value);
setTimeout(()=>{
    promise.then(success,catch);
},1000);

  • 能够看得出 纯回调的形式是先指定回调函数,在咱们想要启动异步任务前就必须指定好成功、失败的回调函数,并且咱们不能在它完成后在指定回调函数,等他执行完毕已经获取不到数据了;

  • 而 promise是经过执行一个函数,这个函数返回一个promise对象,异步操做是在这个Promise对象内部进行的,也就是Promise构造函数执行时当即调用executor 函数,此时异步任务开始了,可是并不须要指定成功、失败的回调函数。

  • 能够再在来看看前面的代码(咱们将代码写的简短一些)

const p = new Promise((resolve, reject) => {
    console.log("executor执行器函数"); //  executor执行器函数
    // 异步任务
    resolve("异步")
})
p.then(value => {
    console.log(value);
})
console.log("new Promise 以后"
  • 打印结果是:   ”executor执行器函数“  、”new Promise 以后“  、“异步”
  • 因此promsie其实不仅是解决回调地狱问题,而说到了回调地狱,其实async函数显得更加优化。

Async函数

  • 什么是async函数

  • ES2017 标准引入了 async 函数,使得异步操做变得更加方便。

  • async 函数是什么?一句话,它就是 Generator 函数的语法糖。

  • 可是我更加倾向于async函数是Promise语法糖。咱们经过下面的例子看看。

 // 以往定义promise的时候
  new Promise((resolve,reject)=>{
    console.log('开始');
    resolve('异步');
  }).then(value => {console.log(value)})
// async函数
  async function fn(){}
  console.log(fn())  // Promise{<fulfilled>:undefined}
  • 能够看得出async 的返回值就是一个Promise对象 而且默认返回一个执行结果为成功的Promise对象,也就是 new Promise() 的语法糖

  • 接着咱们看看 async 下的await

// promise
const promise = new Promise((resolve, reject) => {
    resolve('异步');
})

promise.then(value => {
    console.log(value)
})

// async
async function fn(callback) {
    const val = await callback;
    console.log(val)
}

fn(promise)
}
  • 能够看得出await 就是then的语法糖

  • 接着咱们看看这个语法糖为咱们解决了什么问题

// promise
new Promise((resolve, reject) => {
    resolve(1);
}).then(value => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(value + 1)
        })
    });
}).then(value => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(value + 1)
        })
    });
}).then(value => {
    console.log(value + 1)
})
console.log('我先')

// ascyn 

async function fn() {
    const one = await new Promise((resolve, reject) => {
        resolve(1)
    })
    const two = await new Promise((resolve, reject) => {
        resolve(one + 1)
    })
    console.log(two);
    console.log('我先')
}

fn()
  • 能够看得出 promise的执行会 先打印出 “我先”,而asyn函数 会将异步执行完毕再进行下面的操做,因此async函数不只实现了异步编程,而且在代码的上来讲执行顺序与排列顺序是一致的。

  • 文中说的内容偏入门级别,也是结合本身所学以及理解。

  • 最后想说的是随着前端开发的不断发展,前端开发人员掌握的技术已经再也不是以前的html+css了(俗称的切图仔),而且前端开发人员须要掌握的技术不亚于后端了,甚至须要掌握一些后端知识

  • 本文使用mdnice排版

  • 往期推荐阅读:

  • 从零手写逐步实现Promise A+标准的全部方法

  • 干货!阿里P6手写源码面试题集锦



本文分享自微信公众号 - 前端巅峰(Java-Script-)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索