异步编程
JavaScript是单线程事件环模型编程,异步编程行为是为了面对高延迟优化更高的计算吞吐而产生的。
注意:异步编程不一定是只在高延迟或者计算密集型情况下,可以出现在任何不希望线程阻塞的情况下
早期的异步编程只能使用回调方法进行处理
Promise
Promise基础
在ES6之后,Promise支持引用类型,并且可以使用new操作符创建。
当向console.log传递Promise对象,控制台会打印出Promise对象是挂起状态,Promise是一个状态对象,有三种状态:1、挂起 2、就绪 3、拒绝
Promise的开始状态就是挂起状态,从挂起状态转换,转换到就绪状态表示成功,转为拒绝状态表示失败。这种转换是不可逆的,一但转换到就绪或者拒绝状态,Promise的状态就不会再改变。除此之外不保证Promise对象是否会改变挂起状态。
所以需要注意:设计代码时需要考虑,成功状态,拒绝状态,和无法退出挂起状态,每部分要如何处理
Promise的状态是私有的,不能在JavaScript中直接查看,主要原因是当起状态被读取时,阻止同步编程处理Promise对象,此外,Promise对象不能在JavaScript之外修改。
解析值,拒绝原因,Promise工具
Promise非常实用有两个主要原因:
1、可以抽象表达一段异步执行
2、Promise的状态可以表示Promise是否执行完成,挂起状态可以表示是否执行完毕,或者仍在执行过程中,就绪状态表示执行成功完成,拒绝状态表示没有成功执行完成。
执行器控制Promise的状态
由于Promise的状态是私有的,它只能被内部操作,内部操作需要通过Promise的执行器方法进行处理。
执行器方法主要有两条职责:
1、初始化Promise的异步行为
2、控制最终状态的转换
完成控制状态转换通过函数的两个参数之一,resolve和reject
调用resolve会把状态转为就绪,调用reject会把状态转为拒绝。
Promise转为Promise.resovle()
Promise对象没必要一开始就是挂起状态,执行器可以在创建就改变状态,有下面这两种写法,reject也同理
let p1 = new Promise((resolve, reject) => resolve());
let p2 = Promise.resolve();
Promise.prototype.then()
Promise.prototype.then()是用于处理Promise对象实例的主要方法,可以接收两个可选参数,一个是onResolved处理函数,另一个是onRejected处理函数
当Promise的状态改变会触发Promise.then()
Promise链
Promise链是Promise中的比较实用的技术,可以严格限制Promise的执行顺序,例如
let p = new Promise((resolve, reject) => {
console.log('first');
resolve();
});
p.then(() => console.log('second'))
.then(() => console.log('third'))
.then(() => console.log('fourth'));
Async 函数
async是ES7提供的异步处理关键字,修饰的函数无论返回值是什么,都会被Promise对象覆盖,Promise.resolve()
这两种写法等价
async function foo() {
console.log(1);
return 3;
}
async function foo() {
console.log(1);
return Promise.resolve(3);
}
foo().then(console.log);
console.log(2);
await是必须使用在async修饰函数内部,执行完之后才会执行其他语句,当遇到await关键字,JavaScript运行时可以准确追踪到暂停位置,当await右侧值准备好之后,JavaScript运行时机制会push一个会话到消息队列中,再异步执行之前的那个函数。
注意:await后面可以是任意值,null也可以,仍然会暂停然后异步,如下这个打印1234的例子
async function foo() {
console.log(2);
await null;
console.log(4);
}
console.log(1);
foo();
console.log(3);