最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 面试官对不起!我终于会了Promise...(一面凉经泪目)

    正文概述 掘金(_清水)   2021-04-19   433

    前言

    在下前端小白菜也想找到实习来着,于是乎就面了面。先来给所有的问题给大家分享吧。

    面试题

    • CSS 实现水平垂直居中
    • flex的属性
    • CSS transition的实现效果和有哪些属性
    • CSS 实现沿Y轴旋转360度 (直接自爆了 CSS不行....麻了)
    • 好,那来点JS 基本数据类型有哪些 用什么判断
    • 数组怎么判断
    • 引用类型和基本类型的区别
    • 什么是栈?什么是堆?
    • 手写 翻转字符串
    • 手写 Sum(1,2,3)的累加(argument)(我以为是柯里化,面试官笑了一下,脑筋不要这么死嘛)
    • 箭头函数和普通函数的区别(上题忘记了argument,面试官特意问这个问题提醒我,奈何基础太差救不起来了...泪目)
    • 数组去重的方法
    • 图片懒加载
    • 跨域产生的原因,同源策略是什么
    • 说说你了解的解决办法(只说了JSONP和CORS)
    • Cookie、sessionStorage、localStorage的区别
    • get 和 post 的区别 (只说了传参方式和功能不同,面试官问还有吗 其他的不知道了...)
    • 问了一下项目,react
    • 对ES6的了解 (Promise果真逃不了....)
    • let var const的区别
    • 知道Promise嘛?聊聊对Promise的理解?(说了一下Promise对象代表一个异步操作,有三种状态,状态转变为单向...)
    • 那它是为了解决什么问题的?(emmm当异步返回值又需要等待另一个异步就会嵌套回调,Promise可以解决这个回调地狱问题)
    • 那它是如何解决回调地狱的?(Promise对象内部是同步的,内部得到内部值后进行调用.then的异步操作,可以一直.then .then ...)
    • 好,你说可以一直.then .then ...那它是如何实现一直.then 的?(emmm... 这个.then链式调用就是...额这个...)
    • Promise有哪些方法 all和race区别是什么
    • 具体说一下 .catch() 和 reject (...我人麻了...)

    结束环节

    • 问了面试官对CSS的理解(必须但非重要,前端的核心还是尽量一比一还原设计稿,只有写好了页面才能考虑交互)

    • 如何学习(基础是最重要的,CSS和JS要注重实践,盖房子最重要的还是地基,所有的框架源码,组件等都基于CSS和JS)

    • 曾经是如何度过这个过程的(多做项目,在项目中学习理解每个细节,再次告诫我基础的重要性)

    Promise概述

    Promise是ES6新增的引用类型,可以通过new来进行实例化对象。Promise内部包含着异步的操作。

    这两种方式都会返回一个 Promise 对象。

    • Promise 有三种状态: 等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected),且Promise 必须为三种状态之一只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    • 状态只能由 Pending 变为 Fulfilled 或由 Pending 变为 Rejected ,且状态改变之后不会在发生变化,会一直保持这个状态。
    • Pending 变为 Fulfilled 会得到一个私有value,Pending 变为 Rejected会得到一个私有reason,当Promise达到了Fulfilled或Rejected时,执行的异步代码会接收到这个value或reason。

    知道了这些,我们可以得到下面的代码:

    实现原理

    class Promise {
        constructor() {
            this.state = 'pending'  // 初始化 未完成状态 
            // 成功的值
            this.value = undefined;
            // 失败的原因
            this.reason = undefined;
        }
    }
    

    基本用法

    Promise状态只能在内部进行操作,内部操作在Promise执行器函数执行。Promise必须接受一个函数作为参数,我们称该函数为执行器函数,执行器函数又包含resolve和reject两个参数,它们是两个函数。

    • resolve : 将Promise对象的状态从 Pending(进行中) 变为 Fulfilled(已成功)
    • reject : 将Promise对象的状态从 Pending(进行中) 变为 Rejected(已失败),并抛出错误。

    使用栗子

    let p1 = new Promise((resolve,reject) => {
        resolve(value);
    })
    setTimeout(() => {
        console.log((p1)); // Promise {<fulfilled>: undefined}
    },1)   
    
    let p2 = new Promise((resolve,reject) => {
        reject(reason);
    })
    setTimeout(() => {
        console.log((p2)); // Promise {<rejected>: undefined}
    },1) 
    

    实现原理

    • p1 resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。
    • p2 reject为失败,接收参数reason,状态改变为rejected,不可再次改变。
    • 如果executor执行器函数执行报错,直接执行reject。

    所以得到如下代码:

    class Promise{
        constructor(executor){
          // 初始化state为等待态
          this.state = 'pending';
          // 成功的值
          this.value = undefined;
          // 失败的原因
          this.reason = undefined;
          let resolve = value => {
             console.log(value);
            if (this.state === 'pending') {
              // resolve调用后,state转化为成功态
              console.log('fulfilled 状态被执行');
              this.state = 'fulfilled';
              // 储存成功的值
              this.value = value;
            }
          };
          let reject = reason => {
             console.log(reason);
            if (this.state === 'pending') {
              // reject调用后,state转化为失败态
              console.log('rejected 状态被执行');
              this.state = 'rejected';
              // 储存失败的原因
              this.reason = reason;
            }
          };
          // 如果 执行器函数 执行报错,直接执行reject
          try{
            executor(resolve, reject);
          } catch (err) {
            reject(err);
          }
        }
      }
    

    检验一下上述代码咯:

    class Promise{...} // 上述代码
    
    new Promise((resolve, reject) => {
        console.log(0);
        setTimeout(() => {
            resolve(10) // 1
            // reject('JS我不爱你了') // 2
            // 可能有错误
            // throw new Error('是你的错') // 3    
        }, 1000)
    })
    
    • 当执行代码1时输出为 0 后一秒输出 10fulfilled 状态被执行
    • 当执行代码2时输出为 0 后一秒输出 我不爱你了rejected 状态被执行
    • 当执行代码3时 抛出错误 是你的错

    .then方法

    • 初始化Promise时,执行器函数已经改变了Promise的状态。且执行器函数是同步执行的。异步操作返回的数据(成功的值和失败的原因)可以交给.then处理,为Promise实例提供处理程序。
    • Promise实例生成以后,可以用then方法分别指定resolved状态rejected状态的回调函数。这两个函数onFulfilled,onRejected都是可选的,不一定要提供。如果提供,则会Promise分别进入resolved状态rejected状态时执行。
    • 而且任何传给then方法的非函数类型参数都会被静默忽略。
    • then 方法必须返回一个新的 promise 对象(实现链式调用的关键)

    实现原理

    • Promise只能转换最终状态一次,所以onFulfilledonRejected两个参数的操作是互斥
    • 当状态state为fulfilled,则执行onFulfilled,传入this.value。当状态state为rejected,则执行onRejected,传入this.reason
    class Promise {
        constructor(executor) {
            this.state = 'pending'  // 初始化 未完成状态 
            // 成功的值
            this.value = undefined;
            // 失败的原因
            this.reason = undefined;
    
            // .then 立即执行后 state为pengding  把.then保存起来
            this.onResolvedCallbacks = [];
            this.onRejectedCallbacks = [];
    
            // 把异步任务 把结果交给 resolve
            let resolve = (value) => {
                if (this.state === 'pending') {
                    console.log('fulfilled 状态被执行');
                    this.value = value
                    this.state = 'fulfilled'
                    // onFulfilled 要执行一次
                    this.onResolvedCallbacks.forEach(fn => fn());
                }
            }
            let reject = (reason) => {
                if (this.state === 'pending') {
                    console.log('rejected 状态被执行');
                    this.reason = reason
                    this.state = 'rejected'
                    this.onRejectedCallbacks.forEach(fn => fn());
                }
            }
            try {
                executor(resolve, reject)
            }
            catch (e) {
                reject(err)
            }
        }
        // 一个promise解决了后(完成状态转移,把控制权交出来)
        then(onFulfilled, onRejected) {
            if (this.state == 'pending') {
                this.onResolvedCallbacks.push(() => {
                    onFulfilled(this.value)
                })
                this.onRejectedCallbacks.push(() => {
                    onRejected(this.reason)
                })
            }
            console.log('then');
            // 状态为fulfilled  执行成功  传入成功后的回调  把执行权转移
            if (this.state == 'fulfiiied') {
                onFulfilled(this.value);
            }
            // 状态为rejected 执行失败  传入失败后的回调  把执行权转移
            if (this.state == 'rejected') {
                onRejected(this.reason)
            }
        }
    }
    let p1 = new Promise((resolve, reject) => {
        console.log(0);
        setTimeout(() => {      
            // resolve(10)
            reject('JS我不爱你了')
            console.log('setTimeout');    
        }, 1000)
    }).then(null,(data) => {
        console.log(data, '++++++++++');
    })
    
    0
    then
    rejected 状态被执行
    JS我不爱你了 ++++++++++
    setTimeout
    

    现可以异步实现了,但是还是不能链式调用啊? 为保证 then 函数链式调用,then 需要返回 promise 实例,再把这个promise返回的值传入下一个then中。

    链式调用及后续实现源码

    这部分我也不会,还没看懂。后续再更。 先贴代码:

    class Promise{
      constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            this.onResolvedCallbacks.forEach(fn=>fn());
          }
        };
        let reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn=>fn());
          }
        };
        try{
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      then(onFulfilled,onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        let promise2 = new Promise((resolve, reject) => {
          if (this.state === 'fulfilled') {
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'rejected') {
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'pending') {
            this.onResolvedCallbacks.push(() => {
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0);
            });
            this.onRejectedCallbacks.push(() => {
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0)
            });
          };
        });
        return promise2;
      }
      catch(fn){
        return this.then(null,fn);
      }
    }
    function resolvePromise(promise2, x, resolve, reject){
      if(x === promise2){
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      let called;
      if (x != null && (typeof x === 'object' || typeof x === 'function')) {
        try {
          let then = x.then;
          if (typeof then === 'function') { 
            then.call(x, y => {
              if(called)return;
              called = true;
              resolvePromise(promise2, y, resolve, reject);
            }, err => {
              if(called)return;
              called = true;
              reject(err);
            })
          } else {
            resolve(x);
          }
        } catch (e) {
          if(called)return;
          called = true;
          reject(e); 
        }
      } else {
        resolve(x);
      }
    }
    //resolve方法
    Promise.resolve = function(val){
      return new Promise((resolve,reject)=>{
        resolve(val)
      });
    }
    //reject方法
    Promise.reject = function(val){
      return new Promise((resolve,reject)=>{
        reject(val)
      });
    }
    //race方法 
    Promise.race = function(promises){
      return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
          promises[i].then(resolve,reject)
        };
      })
    }
    //all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
    Promise.all = function(promises){
      let arr = [];
      let i = 0;
      function processData(index,data){
        arr[index] = data;
        i++;
        if(i == promises.length){
          resolve(arr);
        };
      };
      return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
          promises[i].then(data=>{
            processData(i,data);
          },reject);
        };
      });
    }
    
    

    有兴趣的小伙伴可移步

    参考

    Promise的各种方法

    Promise.prototype.catch()

    catch 异常处理函数,处理前面回调中可能抛出的异常。只接收一个参数onRejected处理程序。它相当于调用Promise.prototype.then(null,onRejected),所以它也会返回一个新的Promise

    • 栗子
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(10)  
        }, 1000)
    }).then(() => {
           throw Error("1123")
    }).catch((err) => {
        console.log(err);
    })
    .then(() => {
        console.log('异常捕获后可以继续.then');
    })
    

    当第一个.then的异常被捕获后可以继续执行。

    Promise.all()

    Promise.all()创建的Promise会在这一组Promise全部解决后在解决。也就是说会等待所有的promise程序都返回结果之后执行后续的程序。返回一个新的Promise。

    • 栗子
    let p1 = new Promise((resolve, reject) => {  
        resolve('success1')
    })
    
    let p2 = new Promise((resolve, reject) => {  
        resolve('success1')
    })
    // let p3 = Promise.reject('failed3')
    Promise.all([p1, p2]).then((result) => {  
        console.log(result)   // ['success1', 'success2']             
        
    }).catch((error) => {  
        console.log(error)
    })
    // Promise.all([p1,p3,p2]).then((result) => {  
    //     console.log(result)
    // }).catch((error) => {  
    //     console.log(error) //  'failed3'     
    //     
    // })
    

    有上述栗子得到,all的性质:

    • 如果所有都成功,则合成Promise的返回值就是所有子Promise的返回值数组。
    • 如果有一个失败,那么第一个失败的会把自己的理由作为合成Promise的失败理由。

    Promise.race()

    Promise.race()是一组集合中最先解决或最先拒绝的Promise,返回一个新的Promise。

    • 栗子
    let p1 = new Promise((resolve, reject) => {  
        setTimeout(() => {    
            resolve('success1')  
        },1000)
    })
    
    let p2 = new Promise((resolve, reject) => {  
        setTimeout(() => {    
            reject('failed2')  
        }, 1500)
    })
    
    Promise.race([p1, p2]).then((result) => {  
        console.log(result)
    }).catch((error) => {  
        console.log(error)  //  'success1'    
    })
    

    有上述栗子得到,race的性质:

    • 无论如何,最先执行完成的,就执行相应后面的.then或者.catch。谁先以谁作为回调

    总结

    上面的Promise就总结到这里,讲的可能不太清楚,有兴趣的小伙伴可以看看链接呀,有什么理解也可以在下方评论区一起交流学习。

    面试结束了,面试官人很好,聊的很开心,问题大概都能说上来一点,却总有关键部分忘了hhhhhh,结尾跟面试官聊了一下容易忘这个问题,哈哈哈哈他说我忘就是没学会,以后还是要多总结,多做项目...

    面试可以让自己发现更多的知识盲点,从而促进自己学习,大家一起加油冲呀!!


    起源地下载网 » 面试官对不起!我终于会了Promise...(一面凉经泪目)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元