新特性(下)
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%内容,订阅专栏后可继续查看/也可单篇购买
前端岗位面试求职攻略及真题解析~~