Javascript语言的执行环境是"单线程"(single thread),所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。
为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
同步模式
就是机械一行一行的执行代码直到代码结束,一旦出现问题就执行不下去了。
异步模式
就是执行到异步代码的时候会将这个代码内容暂时挂起,然后继续执行下面内容,当挂起的内容得到响应的时候,又返回来继续执行这个异步代码之后的内容。
js常见的异步操作有:
- setTimeout (setInterval)
- AJAX
- 事件绑定(如:.on,.bind,.listen,.addEventListener,.observe)
- 观察者模式(例如:websocket中就有发布和订阅之类的操作)
- promise 是一个异步操作,但是它是一个异步操作的解决方案,即保存着异步操作的结果,可以把异步函数以同步函数的形式写出来
- async/await — 使用generator的语法糖,可以理解为是generator的一种改进
- generator函数 — 使用promise的语法糖,可以理解为是promise的另一种拓展
异步编程解决方案
回调函数
回调函数就是将一个函数当作另一个主函数的参数来使用的函数。
function test2(){//回调函数
console.log('执行了test2');
}
function test1(callback){ //(主函数)
console.log('执行了test1');
setTimeout(function () {
callback();
}, 1000);
}
// 执行
test1(test2);
解读:回调函数是传统的一种异步编程解决方案,其原理就是将一个函数当作参数传递到另一个主函数中,当主函数执行完自身的内容之后,在运行传递进来的回调函数。这样就达成了类似异步的效果。
缺点:一个任务只能有一个回调函数
用法:回调函数在js中用的还是比较多的,例如:jsonp、ajax、一些常见的需要传递函数当参数来处理一些后续内容的操作
回调函数分为异步回调和同步回调,其实区别就在于主函数中是否执行了异步操作而已
promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,简单地说,Promise好比容器,里面存放着一些未来才会执行完毕(异步)的事件的结果,而这些结果一旦生成是无法改变的
基本使用示例
const promise = new Promise((resolve, reject) => {
resolve(100)
// reject(new Error('promise rejected')) 失败
});
promise.then(function (res) {
return a();
}).catch(function (e) {
catchInfo(e);
})
console.log('end')
Promise((resolve,reject)=>{}),当内部的异步操作完成后就执行resolve,如果出现异常就执行reject即可。resolve对应的是.then()、reject对应的是.catch();
Promise的真正强大之处在于它的多重链式调用,可以避免层层嵌套回调。例如我们在ajax请求后,还要用它返回的结果再次请求,就可以使用Promise,利用then进行「链式回调」,将异步操作以同步操作的流程表示出来。
链式调用示例
let promise = new Promise((resolve, reject) => {
resolve('999')
})
promise.then((value) => {
console.log("成功11", value)
return 100
}).then((value) => {
console.log("成功22", value)
return 200
}).then((value) => {
console.log("成功33", value)
})
async-await
async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象。
async function test() {
let aa = await aa();
console.log(aa)
}
Promise和async/await比较
Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。
async await与Promise一样,是非阻塞的。
async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。