最近一周多得时间一直在面试,那么在面试当中最近被问到很多关于js异步的问题,那么什么是异步呢、常见的异步该怎么实现呢?今天就总结一下关于异步的知识块。
什么是异步?
大家都知道js是单线程的语言,所以它的执行也是从上往下一直执行,不能同时执行多个任务和流程。但是可不可以同时执行多个任务呢,所以js语言就会产生一个同步和异步,比如说小明吃饭和看电视来说,如果说小明吃完饭以后才可以看电视那么此时就是必须完成一件事才可以进行下一件事这样的话就是同步,另一种情况的话就是小明不用等吃完饭就可以看电视,也就是说吃饭和看电视可以同时进行,所以说异步也就是非阻塞模式。
异步实现的几种方法?
1.回调函数
回调函数其实就是把一个函数作为参数传递到另一个函数里,等那个函数执行完后再执行(A函数的参数是B,那么A执行完之后再执行B)。
假定有两个函数A和B,B等待A的执行结果。
function A(callback){
setTimeout(function(){
// A的任务代码
callback();
},1000);
}
A(B);
2. HTML5新属性:async和defer属性
在引入外部js文件的情况下也可以异步加载js
defer属性:IE4.0就出现。defer属声明脚本中将不会有document.write和dom修改。浏览器会并行下载其他有defer属性的script。而不会阻塞页面后续处理。注:所有的defer脚本必须保证按顺序执行的。
<script type="text/javascript" defer></script>
async属性:Html5新属性。脚本将在下载后尽快执行,作用同defer,但是不能保证脚本按顺序执行。他们将在onload事件之前完成。
<script type="text/javascript" defer></script>
3. setTimeout实现异步加载
// 任务一
function fn1() {
console.log(0)
setTimeout(function() {
console.log(1)
}, 0)
}
// 任务二
function fn2() {
console.log(2)
}
fn1()
fn2() // 0 2 1
4.Promise
Promise是ES6新增的内置对象,用于解决异步相关的问题。Promise有三种状态,分别是(1)等待中(pending)(2)完成了(resolved)(3)拒绝了(rejected)它还有两个重要的方法,如果请求成功那么执行then方法,如果失败那么执行catch方法。如果没有依赖的话那么可以使用promise.all。
function promiseAsync(){
let promise = new Promise((resolve, reject) => {
if(success){
// 成功时执行
resolve(fn1)
}else{
// 失败时执行
reject(fn2)
}
})
return promise
}
promiseAsync().then(fn1).catch(fn2)
5.async 及 await
函数加上async那么该函数就会返回一个Promise
async function test() {
return "1"
}
console.log(test()) // -> Promise {<resolved>: "1"}
async和await的配合其实也就是Promise,而且await也就相当于then方法
async function test1() {
await A(name1)
await B(name2)
await C(name3)
}
6.Generator
Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield
语句注明。Generator 函数的执行方法如下。
function* gen(x) {
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器)g
。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针g
的next
方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的yield
语句,上例是执行到x + 2
为止。换言之,next
方法的作用是分阶段执行Generator
函数。每次调用next
方法,会返回一个对象,表示当前阶段的信息(value
属性和done
属性)。value
属性是yield
语句后面表达式的值,表示当前阶段的值;done
属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。