Promise基础用法
new Promise( function(resolve, reject) {...} /* executor */ )
promise是异步请求时会使用,一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)。在调用时候会传入resolve和reject参数,resolve是状态由pending至fulfilled,即状态成功回调。reject是失败回调。
Promise 是用来管理异步编程的,它本身不是异步的,new Promise的时候会立即把executor函数执行
代码片段1:
let p1 = new Promise(()=>{
setTimeout(()=>{
console.log(1)
},0)
console.log(2)
})
console.log(3) // 2 3 1
上面代码会先执行promise中的回调,打印2,然后继续执行打印3,由于打印1延时处理,属于开启的新任务,会等其他任务执行完成,再执行1。
代码片段2:
let p1 = new Promise((resolve,reject)=>{
console.log(1);
resolve('执行promise')
console.log(2)
})
// then:设置成功或者失败后处理的方法
p1.then(result=>{
//p1延迟绑定回调函数
console.log('成功 '+result)
},reason=>{
console.log('失败 '+reason)
})
console.log(3)
// 1
// 2
// 3
// 成功 执行promise
Promise 采用了回调函数延迟绑定技术,在执行 resolve 函数的时候,回调函数还没有绑定,那么只能推迟回调函数的执行。
代码片段2中,先执行打印1,p1中resolve的回调函数还没绑定,会出发微任务,将p1.then暂存起来,继续执行打印2,打印3,同步任务执行完毕后,去执行微任务,执行.then中方法。
代码片段3:
new Promise(resolve=>{
resolve(a) // 报错
// 这个executor函数执行发生异常错误,决定下个then失败方法会被执行
}).then(result=>{
console.log(`成功:${result}`)
return result*10
},reason=>{
console.log(`失败:${reason}`)
// 执行这句时候,没有发生异常或者返回一个失败的Promise实例,所以下个then成功方法会被执行
// 这里没有return,最后会返回 undefined
}).then(result=>{
console.log(`成功:${result}`)
},reason=>{
console.log(`失败:${reason}`)
})
// 失败:ReferenceError: a is not defined
// 成功:undefined
- 不论是成功的方法执行,还是失败的方法执行(then中的两个方法),凡是执行抛出了异常,则都会把实例的状态改为失败。
- 方法中如果返回一个新的Promise实例(比如上例中的Promise.reject(1)),返回这个实例的结果是成功还是失败,也决定了当前实例是成功还是失败。
- 剩下的情况基本上都是让实例变为成功的状态,上一个then中方法返回的结果会传递到下一个then的方法中
async & await
ES7中新增的异步编程方法,async/await的实现是基于 Promise的,简单而言就是async 函数就是返回Promise对象
1、带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。
async function test() {
return 'test'
}
test(); //Promise {<resolved>: "test"}
2、await等待右侧表达式的结果,这个结果是promise对象或者其他值。
遇到await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,继续执行await后面的代码。以下面的代码分析:
async function test1() {
console.log('start test1');
console.log(await test2());
console.log('end test1');
}
async function test2() {
console.log('test2');
return 'return test2 value'
}
test1();
console.log('start async');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('end async');
执行的结果
· 首先执行宏任务,执行test1函数,执行console.log(‘statr test1’)
· 遇到await,先执行右边test2中的console.log(‘test2’),test2())执行完成后返回Promise {: “return test2 value”},是promise对象,推到微任务队列中**,执行test1外面的同步代码
· 执行console.log(‘start async’);
· 遇到setTimeout,推到到下个宏任务队列中
· 执行Promise里面的同步代码console.log(‘promise1’)
· 运行到promise().then,发现是promise对象,推到微任务队列中
· 执行console.log(‘end async’)
· **test1外面的同步代码执行结束后,回到test1中,console.log(await
· 此时第一个宏任务结束,执行所有的微任务,因为微任务队列先进先出,所以先执行console.log(‘return test2 value’) ,执行test2完成后,后面的代码不再阻塞,执行console.log(‘end test1’);后执行console.log(‘promise2’)
· 执行下个宏任务,即执行console.log(‘setTimeout’);
补充下有关宏任务和微任务的知识
宏任务和微任务都是队列,宏任务有script、setTimeout、setInterval等,微任务有Promise.then catch finally、process.nextTick等,宏任务和微任务的关系如下:
先执行第一个宏任务,执行结束后,执行所有的微任务,然后执行下个宏任务。
参考链接:https://www.cnblogs.com/bear-blogs/p/10423759.html