1. promise异步编程
promise
对象代表一个异步操作,有三种状态:pending
(进行中),fulfilled(resolved)
(已成功),rejected
(已失败)。
特点:
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
注: promise状态改变只有两种可能:
pending —> fulfilled
,pending —> rejected
实例方法:
Promise.prototype.then()
:为promise
实例添加状态改变时的回调函数,第一个参数为resolved
状态回调函数,第二个(可选)为rejected
状态的回调函数,返回一个新的promise
实例。Promise.prototype.catch()
:用于指定发生错误时的回调函数,参数为rejected
状态回调函数,返回一个新promise
对象。Promise.prototype.finally()
:用于指定不管promise
对象最后状态如何,都会执行的操作,其回调函数不接受任何参数。
promise基本实例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
promise方法:
Promise.all()
:const p = Promise.all([p1, p2, p3]);
- 只有
p1,p2,p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1,p2,p3
的返回值组成一个数组,传递给p
的回调函数。 - 只要
p1,p2,p3
之中有一个被rejected
,p
的状态就会变成rejected
,此时第一个被rejected
的实例的返回值,会传递给p
的回调函数。
promise.race()
:const p = Promise.race([p1, p2, p3]);
- 只要
p1,p2,p3
之中有一个实例率先改变状态,p
的状态就会跟着改变,且那个率先改变的promise
实例的返回值,就传递给p
的回调函数。
Promise.resolve()/Promise.reject()
:将现有对象转为一个promise
对象。
实现一个完美符合Promise/A+规范的Promise:
function myPromise(
constructor){
let self = this;
self.status = "pending"; //定义状态改变前的初始状态
self.value = undefined; //定义状态为resolved的时候的状态
self.reason = undefined; //定义状态为rejected的时候的状态
function resolve(value){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status === "pending"){
self.value = value;
self.status = "resolved";
}
}
function reject(reason){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status === "pending"){
self.reason = reason;
self.status = "rejected";
}
}
//捕获构造异常
try{
constructor(resolve, reject);
}catch(e){
reject(e);
}
}
//在myPromise的原型上定义链式调用的then方法
myPromise.prototype.then = function(onFullfilled, onRejected){
let self = this;
switch(self.status){
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
2. 升级版异步编程解决方案async/await:
基本实例:
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
关键知识点:
async
函数返回的是一个promise
对象,内部return语句返回的值会成为then方法回调函数的参数。await
是从右向左执行,遇到await
就让出线程,阻塞后面的代码。await
后如果是一个promise
,会等待状态为fulfilled
再返回resolved
的值,如果不是,就直接返回对应的值。async
函数只有内部的异步操作都执行完,才会执行then
方法指定的回调函数。- 如果
await
后面的异步操作出错,那么等同于async
函数返回的promise
对象被reject
。
3. 宏任务与微任务
JS引擎的执行机制:
- 开始执行当前调用栈中的宏任务,过程中如果遇到宏任务,就把它推入【宏任务队列】中,如果遇到微任务,就将其推入【微任务队列】中;
- 在当前宏任务的同步代码执行完毕后,再依次执行队列中所有的微任务;
- 在当前微任务全部执行完毕后,检查渲染,GUI线程接管渲染;
- 渲染完毕后,js线程接管,开始执行队列中的下一个宏任务;
执行流程图如下:
宏任务与微任务定义:
macro-task
(宏任务):当前调用栈中执行的代码,如主代码块script
,setTimeout
,setInterval
等定时器。micro-task
(微任务):当前宏任务执行完,在下一个宏任务开始之前需要执行的任务,如promise.then
,process.nextTick
等。
测试一下以上知识理解:
请问以下代码输出结果是什么?
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' )
}
async function async2() {
console.log( 'async2' )
}
console.log( 'script start' )
setTimeout( function () {
console.log( 'setTimeout' )
}, 0 )
async1();
new Promise( function ( resolve ) {
console.log( 'promise1' )
resolve();
} ).then( function () {
console.log( 'promise2' )
} )
console.log( 'script end' )
正确结果是:
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
你猜对了吗??
参考: