您的位置:首页 > 房产 > 建筑 > Promise相关知识

Promise相关知识

2025/1/23 10:42:13 来源:https://blog.csdn.net/u012997373/article/details/141221644  浏览:    关键词:Promise相关知识

基础知识

event loop事件循环使得JS单线程可以并发的执行异步任务而无需额外创建线程。

JS中的异步任务分为宏任务和微任务。

宏任务:包括setTimeout、setInterval、I/O、UI渲染、事件处理等

微任务:包括Promise的回调(.then, .catch)、MutationObserver、process.nextTick(Node.js特有)等。

event loop的执行顺序

1.整个方法作为一个宏任务执行

2.执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列

3.当前宏任务执行完成后,检查微任务列表,有就依次执行

4.执行浏览器UI线程的渲染工作

5.执行完本轮的宏任务,回到2,循环直到宏任务和微任务都为空。

promise的.then .catch .finally的相关题目

promise.then的时候如果状态不是pending就会把它加入到微任务队列中,如果还是pending状态then不会执行,需要等到被改变状态后才被加入到微任务队列中。

题目一

const promise = new Promise((resolve, reject) => {resolve("success1");reject("error");resolve("success2");
});
promise
.then(res => {console.log("then: ", res);}).catch(err => {console.log("catch: ", err);})output 
"then:success1"

promise的状态一经改变不能再改变

题目二

const promise = new Promise((resolve, reject) => {reject("error");resolve("success2");
});
promise
.then(res => {console.log("then1: ", res);}).then(res => {console.log("then2: ", res);}).catch(err => {console.log("catch: ", err);}).then(res => {console.log("then3: ", res);})outout
"catch: " "error"
"then3: " undefined

catch不管被连接在哪里,都能捕获上层未捕获的错误。而then3被执行是因为catch()也返回一个promise,由于这个promise没有返回值,所以打印出来的是undefined

题目三

Promise.resolve(1).then(res => {console.log(res);return 2;}).catch(err => {return 3;}).then(res => {console.log(res);});output
1
2

promise可以链式调用,不过proomise每次调用.then或者.catch都会返回一个新的promise,从而实现链式调用。

题目四

const promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('timer')resolve('success')}, 1000)
})
const start = Date.now();
promise.then(res => {console.log(res, Date.now() - start)
})
promise.then(res => {console.log(res, Date.now() - start)
})output
'timer'
'success' 1001
'success' 1001

promise的.then或者.catch可以被调用多次,但是promise构造函数只执行一次,promise的内部状态一旦改变,并且有了一个值,后续每次.then或者.catch都会直接拿到这个值。

题目五

Promise.resolve().then(() => {return new Error('error!!!')
}).then(res => {console.log("then: ", res)
}).catch(err => {console.log("catch: ", err)
})output
"then: " "Error: error!!!"

返回任意一个非 promise 的值都会被包裹成 promise 对象,因此这里的return new Error('error!!!')也被包裹成了return Promise.resolve(new Error('error!!!'))

如果你想抛出一个错误,可以用下面的方式

return Promise.reject(new Error('error!!!'));
// or
throw new Error('error!!!')

题目六

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)output
1

.then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传。第一个then和第二个then中传入的都不是函数,一个是数字类型,一个是对象类型,因此发生了透传,将resolve(1) 的值直接传到最后一个then里。

题目七

Promise.reject('err!!!').then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})'error' 'error!!!'

进入的是then()里的第二个参数里面,不会进入catch,如果把第二个参数去掉就进入catch了。

Promise.resolve().then(function success (res) {throw new Error('error!!!')}, function fail1 (err) {console.log('fail1', err)}).catch(function fail2 (err) {console.log('fail2', err)})fail2 Error: error!!!

但如果是在then里面抛出异常,会被catch捕获。

题目八

Promise.resolve('1').then(res => {console.log(res)}).finally(() => {console.log('finally')})
Promise.resolve('2').finally(() => {console.log('finally2')return '我是finally2返回的值'}).then(res => {console.log('finally2后面的then函数', res)})'1'
'finally2'
'finally'
'finally2后面的then函数' '2'

这两个Promise.finally都会执行,且就算finally2返回了新的值,它后面的then()函数接收到的结果却还是'2'。

如果在finally中抛出异常,会被catch捕获。

Promise.resolve('1').finally(() => {console.log('finally1')throw new Error('我是finally中抛出的异常')}).then(res => {console.log('finally后面的then函数', res)}).catch(err => {console.log('捕获错误', err)})'finally1'
'捕获错误' Error: 我是finally中抛出的异常

题目九

而promise的多个链式调用的执行时机又是如何的?需要等到前一个微任务执行完成后,才会继续执行后面的.then或者.finally操作。代码中标注了微任务在队列中的顺利,也就是执行到微任务1的时候,微任务3才进微任务队列,这个时候前面已经有微任务2了。

function promise1 () {let p = new Promise((resolve) => {console.log('promise1');resolve('1')})return p;
}
function promise2 () {return new Promise((resolve, reject) => {reject('error')})
}
promise1().then(res => console.log(res)) // 微任务1.catch(err => console.log(err)).finally(() => console.log('finally1')) // 微任务3promise2().then(res => console.log(res)) .catch(err => console.log(err)) // 微任务2.finally(() => console.log('finally2')) // 微任务4'promise1'
'1'
'error'
'finally1'
'finally2'

promise的all和race

.all():接收一组异步任务并行执行,并在所有异步任务执行完成后才执行回调

.race():接收一组异步任务并行执行,只取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被丢弃。

当一组异步任务中有返回错误的情况,.all()会如何执行?

function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
function runReject (x) {const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]).then(res => console.log(res)).catch(err => console.log(err))// 1s后输出
1
3
// 2s后输出
2
Error: 2
// 4s后输出
4

all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获;但并不会影响数组中其它的异步任务的执行。

race的使用场景:我们可以用race给某个异步任务设置超时事件。

all的使用场景:进入页面并发下载页面所需要的初始化资源,等结果都返回后再刷新页面。

async/await

async function async1() {console.log("async1 start");await async2();console.log("async1 end");
}
async function async2() {console.log("async2");
}
async1();
console.log('start')output
'async1 start'
'async2'
'start'
'async1 end'

await后面的语句相当于放到一个promise中,下一行以及之后的语句相当于放在promise.then中。

async function async1() {console.log("async1 start");// 原来代码// await async2();// console.log("async1 end");// 转换后代码new Promise(resolve => {console.log("async2")resolve()}).then(res => console.log("async1 end"))
}

如果async直接返回一个值,会输出什么?

async function fn () {// return await 1234// 等同于return 123
}
fn().then(res => console.log(res))123

正常是希望得到一个promise对象,如果不是就会直接返回对应的值,等价于promise.resolve() 

未完待续...

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com