新特性(下)
3 新特性(下)
3.1 请问你能手写Promise吗?
【考点映射】
-
Promise结构实现(面试撕代码可能性极大)
【频率】★★★★★
【难度】☆☆☆
【参考答案】
Promise对象是一个构造函数,主要用来生成Promise实例
//创建一个Promise实例
const promise =new Promise(function(resolve, reject){
// ... some code
if(/* 异步操作成功 */){
resolve(value);
}else{
reject(error);
}
});
resolve 函数:将 Promise 对象的状态从 pending → fulfilled ,在异步操作成功时调用,并将异步操作的结果,作为参数传递给注册在 then 方法上的回调函数(then方法的第一个参数);
reject 函数:将 Promise 对象的状态从 pending → rejected ,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递给注册在 then 方法上的回调函数(then方法的第二个参数)
then方法:定义在原型对象 Promise.prototype 上,作用是为 Promise 实例添加状态改变时的回调函数,返回一个新的 Promise 实例(不是原来那个)。第一个参数是 resolved 状态的回调函数,第二个参数是 rejected 状态的回调函数
一步步写出Promise的结构(注意:写法有很多,大家一定要注重思考,理解Promise的工作原理,不要死记硬背一种代码)
下面是ES6版本的整体代码,摘自网络,仅供参考:
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 新建 MyPromise 类
class MyPromise {
constructor(executor){
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
// 储存状态的变量,初始值是 pending
status = PENDING;
// 成功之后的值
value = null;
// 失败之后的原因
reason = null;
// 存储成功回调函数
onFulfilledCallbacks = [];
// 存储失败回调函数
onRejectedCallbacks = [];
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// resolve里面将所有成功的回调拿出来执行
while (this.onFulfilledCallbacks.length) {
// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
this.onFulfilledCallbacks.shift()(value)
}
}
}
// 更改失败后的状态
reject = (reason) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态成功为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
// resolve里面将所有失败的回调拿出来执行
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason)
}
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 获取成功回调函数的执行结果
const x = realOnFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
const rejectedMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 调用失败回调,并且把原因返回
const x = realOnRejected(this.reason);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
// 判断状态
if (this.status === FULFILLED) {
fulfilledMicrotask()
} else if (this.status === REJECTED) {
rejectedMicrotask()
} else if (this.status === PENDING) {
// 等待
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
})
return promise2;
}
// resolve 静态方法
static resolve (parameter) {
// 如果传入 MyPromise 就直接返回
if (parameter instanceof MyPromise) {
return parameter;
}
// 转成常规方式
return new MyPromise(resolve => {
resolve(parameter);
});
}
// reject 静态方法
static reject (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x是不是 MyPromise 实例对象
if(x instanceof MyPromise) {
// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
// x.then(value => resolve(value), reason => reject(reason))
// 简化之后
x.then(resolve, reject)
} else{
// 普通值
resolve(x)
}
}
module.exports = MyPromise;
Promise.all():
将多个Promise,包装成一个新的Promise,只有当所有Promise都成功,新的Promise才成功,一个失败就返回失败的Promise
一些日常开发中十分实用的点:
(1)Promise.all()获得的成功结果的数组里面的数据顺序和Promise.all()接收到的数组顺序是一致的,即便后面的结果返回得慢
(2)Promise.all()可以充分利用并行的优势,返回结果的时间是最长请求的时间,这样可以更快处理请求的结果
Promise.race():
将多个Promise,包装成一个新的Promise,新Promise的结果由第一个完成的Promise决定, 第一个成功则返回成功的Promise,第一个失败直接返回失败的Promise
/*Promise 函数对象all方法,返回一个promise 只有当所有promise都成功,才成功,一个失败就失败*/
function all(promises){
const values = new Array(promises.length) //用来保存所有成功value的数组,长度等于promises的长度
//定义计数器,用来保存成功promise的数量
let resolvedCount = 0
//返回一个新的promise
return new Promise((resolve,reject) =>{
//遍历promises获取每个promise的结果
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
前端岗位面试求职攻略及真题解析~~

