@[toc]
前言:JS是单线程的语言,这意味着它同一时间只能做一件事,当碰到比较耗时的事情的时候,所有后面等待执行的任务就都得原地等待,为了解决这一问题,出现了异步,而异步的执行机制是主线程发送一个异步请求给相应的工作线程,然后主线程去处理其他事情,等到工作现成完成后,浏览器内部的线程会把工作线程的回调函数推入主线程的消息队列,最后主线程执行回调,完成异步操作。
一、Callback
1)Callback 函数的调用在一定程度上是不受我们的控制的,我们缺少可靠的机制确保回调函数能按照预期被执行。
2)难以理解(回调地狱)
二、Promise
是一个对象,从它可以获取异步操作的消息
特点:
1) 对象的状态不受外界影响。有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。
缺点:
1) 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2) 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3) 当处于pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
if (true){
resolve('2313');
} else {
reject('2313');
}
//执行错误,会跳过
console.log('loaded');
});
promise.then(function() {
console.log('resolved.');
setTimeout(() => {
console.log('in setTimeout');
}, 0);
new Promise(function(resolve){
resolve('12');
}).then(() => {
console.log('in Promise');
setTimeout(() => {
console.log('in Promise setTimeout');
}, 0);
});
}).catch(function() {
console.log('rejected.');
}).finally(function() {
console.log('finally');
});
console.log('Hi!');
setTimeout(() => {
console.log('out setTimeout');
}, 0);
then
方法指定的回调函数,在当前脚本所有同步任务执行完才会执行
then/cath
方法返回的是一个新的Promise实例
1、Promise.all
const p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled(已成功)
,p的状态才会变成fulfilled(已成功)
,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected(已失败),p的状态就变成rejected(已失败),此时第一个被reject的实例的返回值,会传递给p的回调函数。
注意,如果作为参数的 Promise 实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()的catch
方法。
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
2、Promise.race
const p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
三、Generator
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
调用 Generator 函数后,该函数并不执行,返回的是遍历器对象(Iterator Object)
必须调用遍历器对象的next方法,每次调用next
方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield
表达式(或return
语句)为止。
yield
表达式是暂停执行的标记,而next
方法可以恢复执行。
yield
表达式后面的表达式,只有当调用next
方法才会执行
function* gen() {
yield 123 + 456;
}
yield
命令后面只能是 Thunk
函数或 Promise
对象
for...of
循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。
next返回值的 value 属性,是 Generator 函数向外输出数据;next方法还可以接受参数,向 Generator 函数体内输入数据。
1、Generator.prototype.throw()
Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
2、Generator.prototype.return()
Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。
• 函数可暂停和继续;
• 可返回多个值给外部;
• 在继续的时候,外面也可以再传入值;
• 通过 Generator 写的异步代码看起来就像是同步的;
四、Async
async
和await
async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果。
async
函数的await
命令后面,可以是 Promise 对象
和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象
)。
async函数
的返回值是 Promise 对象
async函数
完全可以看作多个异步操作,包装成的一个 Promise 对象
,而await
命令就是内部then
命令的语法糖。
以上便是JavaScript中几种异步模式,有时候会被异步搞的乱七八糟,平常用的最多ajax请求,稍微有点不注意,就容易把异步忽略掉,小伙伴们把异步想像成一个脾气暴躁的小朋友,当你遇到他的时候跳过他,该干嘛干嘛去,等把自己的事情做完了,小朋友的脾气也消了,就能回来处理他了。
以上内容参考了沈老师的总结笔记,还有其他小伙伴的博客内容,有涉及侵权的请联系我删除。