什么是异步操作
在JS中,如果当前有3个任务需要执行,分别为A,B,C 如果按照顺序去完成任务的话,如果B是个耗时的任务,那么C的任务是不是要等待B执行结果很长时间,所以这时候就有必要将B放在任务队列中,去执行C任务,然后B的一些I/O等返回结果之后,再去执行B,这就是异步操作。
为什么需要异步操作
- JS的执行环境是单线程的,什么是单线程呢 ? 比方来说,假设进程一想删除某个demo或者元素 ,而进程二想编辑这个demo或者元素,那么如果是多线程的执行环境的话,对同一个demo执行两个不同的进程时候,那么这个demo该执行那一个呢,所以这是自相矛盾的,这也就是为什么JS的执行环境是单线程的。
- 在单线程的执行环境中,执行任务就是按照顺序一个个去执行,如果中间有耗时比较长的操作,例如请求等,那么网页很有可能因为这个耗时过长的任务造成浏览器无响应,后面堆积的任务就无法执行,会拖延整个项目的执行 所以异步操作非常重要,在浏览器端,耗时比较长的操作都应该使用异步操作,避免浏览器失去响应
JS中异步操作的类型
- 回调函数
- 事件监听
- Promise
- await / async
- 发布 / 订阅
- generator (ES6)
一、回调函数
回调函数算是JS中最基础的异步方法了,如果当前有F1,F2,F3的任务需要执行 ,F2是需要等待F1的执行结果,而F3是独立的 ,如果F1执行的比较快,那就可以是同步的,如果F1执行需要耗时,F2和F3都会被阻塞。那么就可以把F2作为F1的回调函数来实现异步操作。
- 同步情况下
F1()
F2()
F3()
- 回调函数处理异步情况下
function F1(callback){
setTimeout(function () {
console.log('这是F1的任务代码')
callback();
}, 1000);
}
F1(F2)
F3()
因为F1是异步的无法得知什么时候完成,这时候就可以用F2作为F1异步的回调函数,在F1异步操作完成后就可以马上执行F2方法,这样就解决了问题
注意
function F1(callback){
console.log('这是F1的任务代码')
callback();
}
F1(F2)
F3()
那么F1在这时候算是异步操作吗? 其实不是的 因为F1并没有使用setTimeout 这个异步函数,传入的callback也只是同步的,不是异步的回调,简单来说就不是真正的回调函数
到这里我们其实可以总结出回调函数其实主要是用来解决异步的问题的
二、Promise
promise也是实现异步编程的一种方式,promise的出现解决了回调地狱,没有层层嵌套的困扰,Promise的知识点还算比较多,下面就是promise的一些特性
- Promise算是一个构造函数, 可以通过new Promise()得到一个promise的实例
- Promise有两个函数 resolve(成功之后的回调),reject(失败之后的回调)
- Promise的propertype上有.then和.catch方法,还有个比较少用的finally方法。也就是说通过new Promise()得到的那个实例也有.then() 和 .catch 方法。(then方法,即任务结束下一步的时候,它可以接收两个回调,成功回调和失败回调) .catch方法是用来捕获错误的。 注意 then方法的第二个参数 和 catch方法都可以捕获到错误,那他们有啥区别呢? 区别在于catch 也可以捕获到then里面第一个参数 也就是resolve里面的异常,但是then不行,所以一般捕获错误用catch这个方法
三、await / async (ES7)
- await / async 是基于Promise 实现的,是非阻塞的
- async函数会隐式地返回一个promise (相当于什么是异步的函数) ,await 等待一个Promise 结束 ,会返回resolve 即成功回调,如果想捕获错误的话 那么可以用 try catch 来捕获
- 二者需要搭配使用
- 相当于Promise 来说 async / await 更加简洁 ,避免了一些then嵌套
总结 :常用的三种异步编程的方式 事件监听是否是异步编程 这个具有争议性,所以就不在这里解释啦