ES6中关于Promise 对象的考法(前端面试必须答对的知识点,必考!!重要!!!!)

    xiaoxiao2022-07-14  175

    一道笔试题帮你梳理多个知识点。请写出以下一段代码输出结果(用逗号隔开)                                        

    setTimeout(function(){ console.log(1); },0) new Promise(function executor(resolve){ console.log(2); for(var i=0;i<1000;i++){ i=9999 && resolve(); } console.log(3); }).then(function(){ console.log(4); }) console.log(5);

     

    先给你运行后的答案 2,3,5,4,1;然后自己思考两分钟,你的答案是什么?

    那么你应该有这么个解题思路

    一、js的执行机制是什么?

      先要搞清楚一个很重要的概念:js是单线程的。JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。

    简单点来说,就是先执行同步的代码,然后在执行异步的代码(如setTimeout、Promise,Ajax操作等);

    二、setTimeout(fn,0)函数

       用处就在于我们可以改变任务的执行顺序!之前讲过,所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务。

    然后呢,setTimeout(fn,0)它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。所以,如下代码:

    setTimeout(function(){ console.log(1); },0) //暂时不分析promise // new Promise(function executor(resolve){ // console.log(2); // // for(var i=0;i<1000;i++){ // // i=9999 && resolve(); // } // // console.log(3); // }).then(function(){ // console.log(4); // }) console.log(5);

    运行结果是5,1没有问题吧!

    三、认识Promise

     Promise不管是面试还是做笔试题都是考察的重中之中。分为三个问题: (1)什么是Promise?

       Promise 是异步编程的一种解决方案,从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败);一旦状态改变,就不会再变,任何时候都可以得到这个结果;

    (2)为什么要用Promise?

       有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

    (3)Promise怎么用?

      Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。resolve函数在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;对应的,reject函数的作用是,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 resolve函数被调用才会被then方法的回调函数接收*/){ resolve(value); } else { reject(error); } });

     Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

    promise.then(function(value) { // success 其中value为异步操作成功时传递出来的参数 }, function(error) { // failure 其中error为异步操作失败时传递出来的参数 });

     

    所以来分析题目中的Promise实例,首先js中的逻辑运算符先了解一下,

    a || b:如果a是true,那么b不管是true还是false,都返回true。因此不用判断b了,这个时候刚好判断到a,因此返回a。    如果a是false,那么就要判断b,如果b是true,那么返回true,如果b是false,返回false,其实不就是返回b了吗。 a && b:如果a是false,那么b不管是true还是false,都返回false,因此不用判断b了,这个时候刚好判断到a,因此返回a。    如果a是true,那么就要在判断b,和刚刚一样,不管b是true是false,都返回b。 在javascript中: 以下内容会被当成false处理:"" , false , 0 , null , undefined , NaN 其他都是true

    请看好同志们,i=9999这个是赋值操作,永远都是true,所以少不了要成功调用resolve()方法,打印出4。

    是的,这个题如果改为i==9999,想必这个resolve()是调用不了了,4也就不能打印了,想象一下,如果题目就是这样出的,你笔试的时候瞅错了,看成i==999了,这是不是又是个让你捶胸顿足的陷阱。

    new Promise(function executor(resolve){ console.log(2); for(var i=0;i<1000;i++){ i=9999 && resolve(); } //console.log(3); }).then(function(){ console.log(4); })

    继续玩一下,你有没有思考过,假如for循环1000次,这个then方法中执行成功的回调函数会执行几次?打印什么?

    new Promise(function executor(resolve){ //console.log(2); for(var i=0;i<1000;i++){ resolve(i); } }).then(function(data){ console.log(data); }) //打印 //0

    果然promise一旦状态改变(成功调用resolve或者reject方法),就不会再变,所以打印0到999是不可能的少年!

    (4)注意

      创造Promise实例后,它会立即执行。

    let promise = new Promise(function(resolve, reject) { console.log('Promise'); resolve(); }); promise.then(function() { console.log('resolved.'); }); console.log('Hi!'); //打印顺序 // Promise // Hi! // resolved

    上述代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。这也引出了,为什么5会在4之前打印。那么3,4的顺序是怎么样的呢?

    这就是另外一个注意的考察点了。调用resolve或reject并不会终结 Promise 的参数函数的执行。

    new Promise((resolve, reject) => { resolve(1); console.log(2); }).then(r => { console.log(r); }); // 2 // 1

    上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。所以,3在4之前打印。而5属于同步任务,所以,综合排序后,最后的结果是2,3,5,4,1。

    (5)最后的最后玩一下

    setTimeout(function(){ console.log(1); },0) new Promise(function executor(resolve){ console.log(2); for(var i=0;i<1000;i++){ i=9999 && resolve(); } console.log(3); }).then(function(){ console.log(4); }) //在来一个 new Promise(function executor(resolve){ console.log(22); for(var i=0;i<1000;i++){ i=9999 && resolve(); } console.log(33); }).then(function(){ console.log(44); }) console.log(5);

    给你结果

    2 3 22 33 5 4 44 1

     

    最新回复(0)