乐趣区

关于promise:前端面试之问到promise怎么办

前言

Promise 作为面试中的经典考题,咱们肯定要粗浅学习和了解它!Promise 有什么用呢?答:咱们拿它解决异步回调问题。Pomise 是 ES6 外面新增的一种异步编程的解决方案。当初这个 promise 在面试中感觉就像“css 革除浮动”一样,属于答不上来就会挂掉的前端基础知识了。

本文纲要:

1.promise 根本用法;

2.promise A+ 手动实现

3.promise 应用中的哪些坑 promise.all 回调天堂等;

(一)promise 根本用法

promise 对象简略的来说,有点相似于 ajax,它能够看做是一个装有某个将来才会完结的事件的容器。它有两个特点:1,promise 的状态不受内部影响;2.promise 的状态一旦扭转,就不会再变了。

能够先看下 promise 的构造

function Promise(executor){

var self = this

self.status = 'pending' // Promise 以后的状态

self.data = undefined // Promise 的值

self.onResolvedCallback = [] // Promise resolve 时的回调函数集,因为在 Promise 完结之前有可能有多个回调增加到它下面

self.onRejectedCallback = [] // Promise reject 时的回调函数集,因为在 Promise 完结之前有可能有多个回调增加到它下面

executor(resolve, reject) // 执行 executor 并传入相应的参数

}

promise 的构造简略来说就是,它有个 status 示意三种状态,pending(挂起),resolve(实现),reject(回绝)。除此之外,它还有两个回调办法onResolvedCallbackonRejectedCallback,别离对应 resolve(实现) 和 reject(回绝)。

如果后面面试官问你 promise 的概念和根本用法,你像我一样提到了 ajax 的话,面试官很可能就会顺口问一下 ajax(毕竟也是前端应该把握得基础知识之一)。依据我的教训来看,一线大厂的面试官这个时候很可能会要你用 promise 撸一个 ajax 进去,一来能够考查你 promise 和 ajax 把握得怎么样,二来能够考查你的代码能力。

1.1 用 promise 来实现 Ajax

const $ = (function(){const ajax = function(url, async = false, type = 'GET'){const promise = new Promise(function(resolve, reject){const handler = function(){if(this.readyState !== 4){return;}

if(this.status === 200){resolve(this.response);

}else{reject(new Error(this.statusText));

}

}

const client = new XMLHttpRequest();

client.open(type, url);

client.onreadystatechange = handler;

client.responseType = 'json';

client.setRequestHeader("Accept", "application/json");

client.send();})

return promise;

}

return {ajax};

})()

调用形式:

$.ajax("/posts.json").then(function(json) {console.log('Contents:' + json);

}, function(error) {console.error('出错了', error);

});

(二)手动实现一个 Promise/A

要留神的几个点:1.then 办法会返回一个新的 promise,因而 then 办法应该写到原型链上。2.promise 的返回值或者抛出的 err 会有传递景象。

例如:

new Promise(resolve=>resolve(8))
.then()
.catch()
.then(function(value) {alert(value)
})

// 依据 promise 的定义和调用形式,能够先写出 promise 的数据结构

function Promise(executor){

const _this = this;

_this.status = 'pending';

_ths.data = undefined;

_this.onRejectedCallback = [];

_this.onResolvedCallback = [];

function resolve(value){if(_this.status === 'pending'){

_this.status = 'resolved';

_this.data = value;

for(let i=0;i<_this.onResolvedCallback.length;i++){_this.onResolvedCallback[i](value);

}

}

}

function reject(reason){if(_this.status === 'pending'){

_this.status = 'rejected';

_this.data = reason;

for(let i=0;i<_this.onResolvedCallback.length;i++){_this.onRejectedCallback[i](reason);

}

}

}

try{executor(resolve, reject);

}catch (e){reject(e)

}

}

// then 办法应该写在原型链上

Promise.prototype.then = function(onResolved, onRejected){

const self = this;

// 要判断 onResolved 和 onRejected 是不是办法

onResolved = typeof onResolved === 'function' ? onResolved : function(value) {return value}

onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {return reason}

if(self.status === 'resolved'){return new Promise(function(resolve, reject){

try{const resoult = onResolved([self.data](https://link.zhihu.com/?target=http%3A//self.data));

if(resoult instanceof Promise){ // 如果返回的是新的 promise,那么用这个 promise 的痛恨办法

resoult.then(resolve, reject)

}

resolve(resoult) // 否则 间接讲返回值作为 newPromise 的后果

}.catch(e){reject(e);

}

});

}

// 此处与前一个 if 块的逻辑简直雷同,区别在于所调用的是 onRejected 函数,就不再做过多解释

if (self.status === 'rejected') {return new Promise(function(resolve, reject) {

try {var resoult = onRejected([self.data](https://link.zhihu.com/?target=http%3A//self.data))

if (resoult instanceof Promise) {resoult.then(resolve, reject)

}

} catch (e) {reject(e)

}

})

}

if(self.status === 'pending'){return new Promise(function(){});

}

if (self.status === 'pending') {

// 如果以后的 Promise 还处于 pending 状态,咱们并不能确定调用 onResolved 还是 onRejected,// 只能等到 Promise 的状态确定后,能力的确如何解决。// 所以咱们须要把咱们的 ** 两种状况 ** 的解决逻辑做为 callback 放入 promise1(此处即 this/self)的回调数组里

// 逻辑自身跟第一个 if 块内的简直统一,此处不做过多解释

return Promise(function(resolve, reject) {self.onResolvedCallback.push(function(value) {

try {var x = onResolved([self.data](https://link.zhihu.com/?target=http%3A//self.data))

if (x instanceof Promise) {x.then(resolve, reject)

}

} catch (e) {reject(e)

}

})

self.onRejectedCallback.push(function(reason) {

try {var x = onRejected([self.data](https://link.zhihu.com/?target=http%3A//self.data))

if (x instanceof Promise) {x.then(resolve, reject)

}

} catch (e) {reject(e)

}

})

})

}

}

(三)promise 的应用中应该要防止哪些坑

在面试的时候,如果能答出来 promise 的应用中可能会呈现什么坑,曾经如何防止这些坑。置信可能给面试官一个好印象,尤其是面试 2 年工作教训的岗位的时候,通过这些就能很好的和培训班毕业的假简历辨别开来。而且这些留神的点也是我自己在我的项目中实实在在踩过的坑。

留神点 1,不要刻意为了丑化代码而防止应用嵌套构造。

很多 promise 的科普教程里,作者都会强调,为了代码的间接性,尽量不要应用嵌套构造。ES7 里还为了解决这个事件,专门设计了 async await 语法。但很多老手,再没有充沛了解业务的前提下,自觉的为了丑化代码,为了防止“回调天堂”,常常会造成很大的问题。

1.1promis.all 的坑

构想一个场景,比方咱们写的一个表单组件。如下图所示:

这里有三个选项组件,每个组件都对应一个字典。过后组里的一个实习生,为了简洁丑化代码,在这样一个组件里应用的 Promise.all()。

相似于这样:

fetchData1 = function (){ // 申请组件 1 的字典};fetchData2 = function (){ // 申请组件 2 的字典};fetchData3 = function (){ // 申请组件 3 的字典};Promise.all([fetchData1, fetchData2, fetchData3]);

过后看这段代码,并没有发现什么问题。后果起初一生产环境,问题就进去,控件 1 硬是获取不到字典项,然而获取组件 1 字典的接口,怎么查都是好的。最初只能从新看一遍组件的源代码,才发现了问题。原理是控件 2 的接口呈现了问题,导致于整个 Promise.all 申请报错。

所以,在应用 promise.all 的时候要留神:业务上没有必然关联的申请比方联动组件这种,肯定不要应用 promise.all。

2. 回调天堂并不可怕,不要自觉的应用async await

上面是比拟常见的前端代码:

asycn ()=>{

await 获取订单 1 的数据;

await 获取订单 2 的数据;

......

}

当订单 2 的数据与订单 1 的数据间接没有相互依赖的关系的时候。获取订单 2 的执行工夫就多了一倍的订单 1 的工夫。同样的情理,如果前面还有订单 3,订单 4,那节约的工夫就更多了。这也是会造成前端页面卡顿的次要起因。

面对这样的常考题型,我感觉也要认真对待,因为面试中如果仅仅只是背答案,也很可能会挂掉。如果面试官看进去你在背答案,他只须要把相干的知识点都问一下,或者让你手动实现一下,又或者问你在我的项目中遇到了什么坑,你是怎么解决的。筹备不充沛的面试者,一下子就会露出马脚。

所以小编为大家筹备了前端面试题材料,之前小编把前端面试问题的知识点整顿成 PDF 文档,不便本人查阅学习,当初收费分享给大家,小编新建了一个前端学习圈,欢送大家退出学习聊天哦~ 心愿大家在外面有所播种也聊得开心!小伙伴们 点击这里 进群玩并取材料哦!

最近和小伙伴聊天理解到面试问题问 vue 比拟多些,小编把 vue 相干的面试材料一起分享给大家,也是一样点击这里收费获取哦!

篇幅无限,小编没有展现完,须要文章中呈现的全副材料的,点击获取起源:前端面试题材料就好喽,祝各位能在本人的人生找到属于本人的职场生涯!

退出移动版