这套题还不错,感兴趣的猿可以试一试:前端开发工程师
1、如何实现一个 sleep
函数(延迟函数)
通过 promise
和 setTimeout
来简单实现
/**
* 延迟函数
* @param {Number} time 时间
*/
function sleep (time = 1500) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, time)
})
}
2、promise
构造函数、then
方法、catch
方法、finally
方法哪个异步哪个同步?
promise
构造函数是同步执行的,then
、catch
和 finally
方法是异步执行的。
3、如何取消一个 promise
?
1. 使用 promise.race()
Promise.race(iterable)
当 iterable
参数里的任意一个子 promise
被成功或失败后,父 promise
马上也会用子 promise
的成功返回值或失败详情作为参数调用父 promise
绑定的相应句柄,并返回该 promise
对象。
/**
* @author guoqiankunmiss
*/
//封装一个取消promise的函数,使用promise.race的特性
function stopPromise (stopP) {
let proObj = {};
let promise = new Promise((resolve, reject) => {
proObj.resolve = resolve;
proObj.reject = reject;
})
proObj.promise = Promise.race([stopP, promise])
return proObj
}
//一个5秒钟之后执行的.then方法的promise
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 5000);
});
//调用函数
let obj = stopPromise(promise);
//收集返回值
obj.promise.then(res => {
console.log(res);
});
//两秒钟之后进行取消promise操作
setTimeout(() => {
obj.resolve("Promise 请求被取消了!");
}, 2000)
4、多个 promise
如何获取第一个成功promise
?
1. Promise.all
改进
利用 promise.all
的特性,遍历 promise
数组,根据返回值进行判断,当成功的时候,转为 reject
返回,当失败的时候转为 resolve
继续执行。
//第一个成功的Promise
function firstProSuccess (allProMise) {
//遍历promise数组,根据返回值进行判断,当成功的时候,转为reject返回,当失败的时候转为resolve继续执行。
return Promise.all(allProMise.map(item => {
return item.then(
res => Promise.reject(res),
err => Promise.resolve(err)
)
})).then(
errors => Promise.reject(errors),
val => Promise.resolve(val)
)
}
2. Promise.any
Promise.any(iterable)
接收一个 Promise
对象的集合,当其中的一个 promise
成功,就返回那个成功的 promise
的值。
缺点:有兼容问题
5、多个 promise
,所有的 promise
都取得返回结果(不管成功/失败都要返回值)
1. Promise.all
改进
和上面原理类似,只不过是当成功的时候不进行操作,当 reject
时进行 resolve
操作
2. Promise.allSettled()
Promise.allSettled(iterable)
返回一个在所有给定的 promise
都已经 fulfilled
或 rejected
后的 promise
。
缺点:有兼容问题
6、说说 promise
的静态方法有哪些?
1. Promise.all(iterable)
接收一个 promise
数组对象(可迭代的 promise
实例对象),全部成功时,返回所有 promise
的数组集合;当其中一个失败时,返回当前失败的 promise
对象。
2. Promise.allSettled(iterable)
接收一个 promise
数组对象,全部完成时(不管成功/失败)返回新的 promise
数组集合
3. Promise.any(iterable)
接收一个 promise
数组对象,当其中任何一个成功时,返回成功的 promise
值
4. Promise.race(iterable)
接收一个 promise
数组对象,当其中任意一个成功/失败时,返回该 promise
值
5. Promise.reject(reason)
返回一个状态为失败的 Promise
对象。
6. Promise.resolve(value)
返回一个状态由给定 value
决定的 Promise
对象。
7. Promise.finally(onFinally)
在当前 promise
运行完毕后被调用,无论当前 promise
的状态是完成( fulfilled
)还是失败( rejected
)
8. Promise.try(f)
接收一个函数,返回一个 promise
。
为所有操作提供了统一的处理机制,所以如果想用 then
方法管理流程,最好都用 Promise.try
包装一下。
- 更好的错误处理
- 更好的互操作性
- 易于浏览
7、Promise.then
的第二个参数有了解吗?和 .catch
有什么区别?
then()
方法返回一个 Promise
。
它最多需要有两个参数:Promise
的成功和失败情况的回调函数。
p.then(onFulfilled[, onRejected]);
p.then(value => {
// fulfillment
}, reason => {
// rejection
});
第二个参数也是一个函数,是对失败情况的回调函数。
then 第二个参数 |
catch |
---|---|
then 方法的参数 |
Promise 的实例方法 |
then 的第一个参数抛出异常捕获不到 |
then 的第一个参数抛出异常可以捕获 |
是一个函数 | 本质是 then 方法的语法糖 |
如果第二个参数和 catch 同时存在,promise 内部报错,第二个参数可以捕获 |
此时,catch 捕获不到,第二个参数不存在,catch 才会捕获到 |
不建议使用 | 建议使用 catch 进行错误捕获 |
8、Promise.resolve
有几种情况?
1. 参数是一个 Promise
实例
参数是 Promise
实例,那么 Promise.resolve
将不做任何修改、原封不动地返回这个实例。
2. 参数是一个 thenable
对象
Promise.resolve()
方法会将这个对象转为 Promise
对象,然后就立即执行 thenable
对象的 then()
方法。
3. 参数不是具有 then()
方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有 then()
方法的对象,则 Promise.resolve()
方法返回一个新的 Promise
对象,状态为 resolved
。
4. 不带有任何参数
直接返回一个 resolved
状态的 Promise
对象。
9、如果 .then
中的参数不是函数,那会怎样?
Promise.resolve(1)
.then(2)
.then(console.log)
// 1
如果 .then
中的参数不是函数,则会在内部被替换为 (x) => x
,即原样返回 promise
最终结果的函数。
10、如果 .finally
后面继续跟了个 .then
,那么这个 then
里面的值是什么?
Promise.resolve('resolve')
.finally(() => {
console.log('this is finally')
return 'finally value'
})
.then(res => {
console.log('finally后面的then函数, res的值为:', res)
})
// this is finally
finally
后面的 then
函数, res
的值为: resolve
finally
的回调函数中不接收任何参数;- 在
promise
结束时,无论结果是fulfilled
或者是rejected
,都会执行finally
回调函数; finally
返回的是一个上一次的Promise
对象值。
11、.all
和 .race
在传入的数组有第一个抛出异常的时候,其他异步任务还会继续执行吗?
会的,会继续执行,只是不会在 then / catch
中表现出来。
浏览器执行下面代码,可以看出当报错的时候 console
还是会继续执行的,只是在 对应的回调函数里面没有表现出来。
function sleep (n) {
return new Promise((resolve, reject) => {
console.log(n)
Math.random() > 0.5 ? reject(n) : resolve(n)
}, n % 2 === 0 ? 1000 * n : 1000)
}
Promise.all([sleep(1), sleep(2), sleep(3)])
.then(res => console.log('all res: ', res))
.catch(err => console.log('all err:', err))
Promise.race([sleep(1), sleep(2), sleep(3)])
.then(res => console.log('race res: ', res))
.catch(err => console.log('race err:', err))
12、.all
是并发的还是串行的?
是并发的,但是返回值和 promise.all
中接收到的数组顺序一样。
13、promise
为什么可以进行链式调用
因为 then
、catch
、finally
方法会返回一个新的 promise
,所以允许我们进行链式调用。
14、async/await
1. 实现原理
async
函数是基于 generator
实现,所以涉及到 generator
相关知识。 在没有async
函数之前,通常使用 co
库来执行 generator
,所以通过 co
我们也能模拟 async
的实现。
2. 简单实现
1)co
库
function Asyncfn() {
return co(function*() {
//.....
});
}
function co(gen) {
return new Promise((resolve, reject) => {
const fn = gen();
function next(data) {
let { value, done } = fn.next(data);
if (done) return resolve(value);
Promise.resolve(value).then(res => {
next(res);
}, reject);
}
next();
});
}
2)Generator
函数和自执行器
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch (e) {
return reject(e);
}
if (next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(
function(v) {
step(function() {
return gen.next(v);
});
},
function(e) {
step(function() {
return gen.throw(e);
});
}
);
}
step(function() {
return gen.next(undefined);
});
});
}