前端面试题目100及最佳答案(前端Promise)
一 、Promise的理解与使用
抽象表达:
Promise是ES6新增的一种语法 ,是异步编程的一种解决方案 。(旧方案是单纯的使用回调函数)
异步编程:fs文件操作 、数据库操作 、Ajax 、定时器 。
具体表达:
(1)从语法上说 ,promise是一种构造函数
(2)从功能上说 ,promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值 。
1. Promise的状态
三种状态:
pending(进行中 ,初始状态)
fulfilled(成功状态 ,也叫resolved)
rejected(失败状态)
Promise只有两个过程(状态):
(1)pending -> fulfilled : Resolved(已完成)
(1)pending -> rejected:Rejected(已拒绝)
通过函数resolve将状态转为fulfilled ,函数reject将状态转为rejected ,状态一经改变就不可以再次变化 。
一个 promise 对象只能改变一次 , 无论变为成功还是失败, 都会有一个结果数据 ,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason 。
2. Promise的状态可变吗?
一经改变不能再改变 。
3. Promise的基本流程
4. Promise的基本使用
function doDelay(timeout){ // 创建一个新的promise对象并返回 return new Promise((resolve, reject) => { // 执行器函数 // 执行异步操作任务 setTimeout(() => { const time = Date.now() // 如果当前时间是偶数代表成功 ,否则失败 if (time % 2 === 0) { // 如果成功 ,调用resolve(value) resolve(成功的数据 ,time= + time) } else { // 如果失败,调用reject(reason) reject(失败的数据 ,time= + time) } }, timeout); }) } let promise = doDelay(1000) //.then() 和执行器(executor)同步执行 ,.then() 中的回调函数异步执行 promise.then( value => { // 接收得到成功的value数据 onResolved console.log(成功的回调, value) // 成功的回调 成功的数据 }, reason => { // 接收得到失败的reason数据 onRejected console.log(失败的回调, reason) // 失败的回调 失败的数据 } )使用promise封装ajax异步请求 。
function promiseAjax(url){ // 创建一个新的promise对象并返回 return new Promise((resolve, reject) => { // 执行器函数 const xhr = new XMLHttpRequest(); xhr.onreadystatechange=()=>{ if(xhr.readyState!==4) return; const {status,response} =xhr; if(status>=200&&status<300){ resolve(JSON.parse(response)) }else{ reject(new Error("失败,status:"+status)) } } xhr.open("GET",url); xhr.send() }) } let promise = promiseAjax(xxx) promise.then( data => { console.log(成功的回调, data) }, error => { console.log(失败的回调, error.message) } )二 、为什么要用Promise?
特点:
(1)将异步操作以同步操作的流程表达出来 ,避免了层层嵌套的回调函数 。流程更加清晰 ,代码更加优雅 。
(2)Promise对象提供统一的接口 ,使得控制异步操作更加容易 。
缺点:
(1)无法取消Promise ,一旦新建它就会立即执行 ,无法中途取消 。
(2)如果不设置回调函数 ,Promise内部抛出的错误 ,不会反应到外部 。
(3)当处于pending状态时 ,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
1. 指定回调函数的方式更加灵活
promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
2. 支持链式调用 ,可以解决回调地狱问题
(1)什么是回调地狱?
回调函数嵌套使用 ,外部回调函数异步执行的结果是嵌套的回调执行条件 。具体来说就是异步返回值又依赖于另一个异步返回值(看下面的代码)
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log(Got the final result: + finalResult) }, failureCallback) }, failureCallback) }, failureCallback)(2)回调地狱的缺点?
不便于阅读 、不便于异常处理
(3)解决方案?
promise链式调用
doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => {console.log(Got the final result: + finalResult)}) .catch(failureCallback)(4)终极解决方案async/await
async function request() { try{ const result = await doSomething() const newResult = await doSomethingElse(result) const finalResult = await doThirdThing(newResult) console.log(Got the final result: + finalResult) } catch (error) { failureCallback(error) } }三 、如何使用Promise?
1. Promise 构造函数:Promise(executor) {}
executor 函数:同步执行 (resolve, reject) => {}
resolve 函数:内部定义成功时调用的函数 resove(value)
reject 函数:内部定义失败时调用的函数 reject(reason)
说明:executor 是执行器 ,会在 Promise 内部立即同步回调 ,异步操作 resolve/reject 就在 executor 中执行
let p = new Promise((resolve,reject)=>{ console.log(1111) }) console.log(222) //输出结果 //111 //2222. Promise.prototype.then 方法:p.then(onResolved, onRejected)
指定两个回调(成功+失败)
onResolved 函数:成功的回调函数 (value) => {}
onRejected 函数:失败的回调函数 (reason) => {}
说明:指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象 。
3. Promise.prototype.catch 方法:p.catch(onRejected)
指定失败的回调
onRejected 函数:失败的回调函数 (reason) => {}
function doDelay(timeout){ // 创建一个新的promise对象并返回 return new Promise((resolve, reject) => { // 执行器函数 // 执行异步操作任务 setTimeout(() => { const time = Date.now() // 如果当前时间是偶数代表成功 ,否则失败 if (time % 2 === 0) { // 如果成功 ,调用resolve(value) resolve(成功的数据,time= + time) } else { // 如果失败 ,调用reject(reason) reject(失败的数据 ,time= + time) } }, timeout); }) } let promise = doDelay(1000) promise.then( value => { // 接收得到成功的value数据 onResolved console.log(成功的回调, value) // 成功的回调 成功的数据 }, ).catch( reason => { // 接收得到失败的reason数据 onRejected console.log(失败的回调, reason) // 失败的回调 失败的数据 } )说明:这是then() 的语法糖 ,相当于 then(undefined, onRejected)
4. Promise.resolve 方法:Promise.resolve(value)
是promise这个函数对象的 ,并不属于实例对象。
value:将被 Promise 对象解析的参数 ,也可以是一个成功或失败的 Promise 对象
返回:返回一个带着给定值解析过的 Promise 对象 ,如果参数本身就是一个 Promise 对象 ,则直接返回这个 Promise 对象 。
作用:快速得到Promise对象 ,一个封装一个值 ,将这个值转换为Promise对象
(1)如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
let p1 = Promise.resolve(521); console.log(p1); // Promise {<fulfilled>: 521}(2)如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => { // resolve(OK); // 成功的Promise reject(Error); })); console.log(p2); p2.catch(reason => { console.log(reason); })5. Promise.reject 方法:Promise.resolve(reason)
reason:失败的原因
说明:返回一个失败的 promise 对象
let p = Promise.reject(521); let p2 = Promise.reject(iloveyou); let p3 = Promise.reject(new Promise((resolve, reject) => { resolve(OK); })); console.log(p); console.log(p2); console.log(p3);Promise.resolve()/Promise.reject() 方法就是一个语法糖
用来快速得到Promise对象
6. Promise.all 方法:Promise.all(iterable)
iterable:包含 n 个 promise 的可迭代对象 ,如 Array 或 String
说明:返回一个新的 promise ,只有所有的 promise 都成功才成功 ,只要有一个失败了就直接失败 。
let p1= new Promise((resolve,reject)=>{ resolve("success") }) let p2 = Promise.resolve(success) let p3 = Promise.resolve(yet) let p4 = Promise.reject(error) const res = Promise.all([p1,p2,p3]); res.then( value => { console.log(res成功的回调, value) }, reason => { console.log(res失败的回调, reason) } ) const res2 = Promise.all([p1,p2,p3,p4]); res2.then(//p4失败,所以res2失败 value => { console.log(res2成功的回调, value) }, reason => { console.log(res2失败的回调, reason) } )let p1= new Promise((resolve,reject)=>{ resolve("success") }) let p2 = Promise.resolve(success) let p3 = Promise.resolve(yet) let p4 = Promise.reject(error) const res = Promise.all([p1,p2,p3]); const res2 = Promise.all([p1,p2,p3,p4]); console.log(res) console.log(res2)7. Promise.race方法:Promise.race(iterable)
iterable:包含 n 个 promise 的可迭代对象 ,如 Array 或 String
说明:返回一个新的 promise ,第一个完成的 promise 的结果状态就是最终的结果状态,谁先完成就输出谁(不管是成功还是失败)
let p1= new Promise((resolve,reject)=>{ setTimeout(() => { resolve(1) }, 1000) }) let p2 = Promise.resolve(2) let p3 = Promise.resolve(3) let p4 = Promise.reject(4) //谁先完成就输出谁(不管是成功还是失败) const res = Promise.race([p1,p2,p3,p4]); res.then(//2先执行 ,输出2 value => {//res成功的回调 2 console.log(res成功的回调, value) }, reason => { console.log(res失败的回调, reason) } ) const res2 = Promise.all([p4,p2,p3,p1]); res2.then(//4先执行 ,输出4 value => {//res2失败的回调 4 console.log(res2成功的回调, value) }, reason => { console.log(res2失败的回调, reason) } )8.Promise.any()
区别于Promise.all(), Promise.any() 只要有一个成功 ,就返回成功的promise ,如果没有一个成功 ,就返回一个失败的promise 。
9.Promise.allSelected()
Promise.allSelected([]).then(res => {}).catch(err => {})
返回一个在所有给定的promise都已经fulfilled或rejected后的promise ,并带有一个对象数组 ,每个对象表示对应的promise结果
const promise1 = Promise.resolve(3); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, foo)); const res= Promise.allSettled([promise1,promise2]) res.then( results=>results.forEach(result=>console.log(result)) )四 、Promise的几个关键问题
1. 如何改变 promise 的状态?
(1)resolve(value):如果当前是 pending 就会变为 resolved
(2)reject(reason):如果当前是 pending 就会变为 rejected
(3)抛出异常:如果当前是 pending 就会变为 rejected
const p = new Promise((resolve, reject) => { //resolve(1) // promise变为resolved成功状态 //reject(2) // promise变为rejected失败状态 throw new Error(出错了) // 抛出异常 ,promise变为rejected失败状态 ,reason为抛出的error }) p.then( value => {}, reason => {console.log(reason,reason)} ) // reason Error:出错了2. 一个 promise 指定多个成功/失败回调函数 ,都会调用吗?
当 promise 改变为对应状态时都会调用
const p = new Promise((resolve, reject) => { resolve(1) // reject(2) }) p.then( value => {console.log(value,value)}, reason => {console.log(reason,reason)} ) p.then( value => {console.log(value2,value)}, reason => {console.log(reason2,reason)} ) // value 1 // value 1 // reason 2 // reason2 23. 改变 promise 状态(resolve 、reject 、throw)和指定回调函数(then,catch)谁先谁后?
都有可能 ,常规是先指定回调再改变状态 ,但也可以先改状态再指定回调
如何先改状态再指定回调?
(1)在执行器中直接调用 resolve()/reject()
(2)延迟更长时间才调用 then()
let p = new Promise((resolve, reject) => { resolve(OK);//执行器函数中的任务是同步任务,直接调动resolve,这是先改变状态 ,后执行回调 // setTimeout(() => { //resolve(OK); // }, 1000); // 有异步就先指定回调 ,否则先改变状态 }); p.then(value => { console.log(value); },reason=>{ })什么时候才能得到数据?
(1)如果先指定的回调,那当状态发生改变时 ,回调函数就会调用得到数据
(2)如果先改变的状态 ,那当指定回调时 ,回调函数就会调用得到数据
new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 改变状态 }, 1000) }).then( // 指定回调函数 (先指定) value => {}, reason =>{} )此时 ,先指定回调函数 ,保存当前指定的回调函数;后改变状态(同时指定数据) ,然后异步执行之前保存的回调函数 。
new Promise((resolve, reject) => { resolve(1) // 改变状态 }).then( // 指定回调函数 value => {}, reason =>{} )这种写法 ,先改变的状态(同时指定数据) ,后指定回调函数(不需要再保存) ,直接异步执行回调函数
4. promise.then() 返回的新 promise 的结果状态由什么决定?
(1)简单表达:由 then() 指定的回调函数执行的结果决定
let p = new Promise((resolve, reject) => { resolve(ok); }); //执行 then 方法 let result = p.then(value => { console.log(value); }, reason => { console.warn(reason); }); console.log(result);(2)详细表达:
① 如果抛出异常 ,新 promise 变为 rejected ,reason 为抛出的异常
let p = new Promise((resolve, reject) => { resolve(ok); }); //执行 then 方法 let result = p.then(value => { //1. 抛出错误 throw 出了问题; }, reason => { console.warn(reason); }); console.log(result);② 如果返回的是非 promise 的任意值 ,新 promise 变为 resolved,value 为返回的值
let p = new Promise((resolve, reject) => { resolve(ok); }); //执行 then 方法 let result = p.then(value => { //2. 返回结果是非 Promise 类型的对象 return 521; }, reason => { console.warn(reason); }); console.log(result);③ 如果返回的是另一个新 promise ,此 promise 的结果就会成为新 promise 的结果
let p = new Promise((resolve, reject) => { resolve(ok); }); //执行 then 方法 let result = p.then(value => { //3. 返回结果是 Promise 对象 return new Promise((resolve, reject) => { // resolve(success); reject(error); }); }, reason => { console.warn(reason); }); console.log(result);5.promise 如何串联多个操作任务?
(1)promise 的 then() 返回一个新的 promise ,可以并成 then() 的链式调用
(2)通过 then 的链式调用串联多个同步/异步任务
let p = new Promise((resolve, reject) => { setTimeout(() => { resolve(OK); }, 1000); }); p.then(value => { return new Promise((resolve, reject) => { resolve("success"); }); }).then(value => { console.log(value); // success }).then(value => { console.log(value); // undefined }) new Promise((resolve, reject) => { setTimeout(() => { console.log(执行任务1(异步)) resolve(1) }, 1000) }).then( value => { console.log(任务1的结果, value) console.log(执行任务2(同步)) return 2 // 同步任务直接return返回结果 } ).then( value => { console.log(任务2的结果, value) return new Promise((resolve, reject) => { // 异步任务需要包裹在Promise对象中 setTimeout(() => { console.log(执行任务3(异步)) resolve(3) }, 1000) }) } ).then( value => { console.log(任务3的结果, value) } ) // 执行任务1(异步) // 任务1的结果 1 // 执行任务2(同步) // 任务2的结果 2 // 执行任务3(异步) // 任务3的结果 36.Promise 异常穿透(传透)?
在最后加一个catch方法
(1)当使用 promise 的 then 链式调用时,可以在最后指定失败的回调
(2)前面任何操作出了异常 ,都会传到最后失败的回调中处理
new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log(onResolved1(), value) return 2 } ).then( value => { console.log(onResolved2(), value) return 3 } ).then( value => { console.log(onResolved3(), value) } ).catch( reason => { console.log(onRejected1(), reason) } ) // onRejected1() 1相当于这种写法:多写了很多reason => {throw reason}
new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log(onResolved1(), value) return 2 }, reason => {throw reason} // 抛出失败的结果reason ).then( value => { console.log(onResolved2(), value) return 3 }, reason => {throw reason} // 抛出失败的结果reason ).then( value => { console.log(onResolved3(), value) }, reason => {throw reason} // 抛出失败的结果reason ).catch( reason => { console.log(onRejected1(), reason) } ) // onRejected1() 17.中断 promise 链?
当使用 promise 的 then 链式调用时 ,在中间中断 ,不再调用后面的回调函数
办法:在回调函数中返回一个 pending 状态的 promise 对象 ,return new Promise(() => {})
new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log(onResolved1(), value) return 2 } ).then( value => { console.log(onResolved2(), value) return 3 } ).then( value => { console.log(onResolved3(), value) } ).catch( reason => { console.log(onRejected1(), reason) } ).then( value => { console.log(onResolved4(), value) }, reason => { console.log(onRejected2(), reason) } ) // onRejected1() 1 // onResolved4() undefined为了在 catch 中就中断执行 ,可以这样写 ,return new Promise(() => {}) :
new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log(onResolved1(), value) return 2 } ).then( value => { console.log(onResolved2(), value) return 3 } ).then( value => { console.log(onResolved3(), value) } ).catch( reason => { console.log(onRejected1(), reason) return new Promise(() => {}) // 返回一个pending的promise } ).then( value => { console.log(onResolved4(), value) }, reason => { console.log(onRejected2(), reason) } ) // onRejected1() 1在 catch 中返回一个新的 promise ,且这个 promise 没有结果 。
由于 ,返回的新的 promise 结果决定了后面 then 中的结果 ,所以后面的 then 中也没有结果 。
这就实现了中断 promise链的效果 。
五 、 async await 和Promise
1.执行async函数 ,返回的都是Promise对象
async function test1() { return 1; }; async function test2() { return Promise.resolve(1); }; const res1 = test1(); const res2 = test2(); console.log(res1, res1); console.log(res2, res2);2.Promise.then 成功的情况 ,对应的是await
async function test3() { const p3 = Promise.resolve(3); p3.then(data => { console.log(data,data); }); const data = await p3; console.log(data); } test3(); //data 3 //33.Promise.catch 异常的情况 , 对于try…catch…
async function test3() { const p3 = Promise.reject(3); p3.catch(data => { console.log(data,data); }); try { const data = await p3; console.log(data,data); } catch (err) { console.log(err, err); } } test3(); //data 3 // error 34. 如何让Promise顺序执行?应用场景是什么?
const p1 = new Promise(resolve => { setTimeout(()=> { resolve(1); }, 3000); }); const p2 = new Promise(resolve => { setTimeout(()=> { resolve(2); }, 2000); }); const p3 = new Promise(resolve => { setTimeout(()=> { resolve(3); }, 1000); }); async function execute() { await p1.then(data => console.log(data)); await p2.then(data => console.log(data)); await p3.then(data => console.log(data)); }; execute(); //1 //2 //3六 、常见面试题
Promise面试题汇总_CUG-GZ的博客-CSDN博客_promise面试题
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!