cdt规约报文用程序解析_用JavaScript Promise迷你书解析一道promise必考面试题(文末小程序送书)...

本文通过讲解JavaScript Promise迷你书的前两章有关Promise的关键知识来解析一道常考的promise面试题-手动实现Promise.all。  第一章主要介绍了如何编写promise代码:

bfc3b76bbdcfa81d930d6bb682f40747.png

第二章为promise实战延伸,只提取了3个常用的知识点:

70fb38deb8f818b292eabf7db6d6ecde.png

可能光是看知识点不能完全理解,下面会结合手动实现Promise.all来应用上面的知识点。首先看一下promise.all的使用示例:
var p1 = Promise.resolve(1),    p2 = Promise.resolve(2),    p3 = Promise.resolve(3);Promise.all([p1, p2, p3]).then(function (results) {    console.log(results);  // [1, 2, 3]});
Promise.all接收一个promise数组,返回一个promise实例,then回调函数参数为promise满足返回值的数组,与Promise.all接收的promise实例相对应。 如果有一个promise变成reject状态,就执行catch方法:
var p1 = Promise.resolve(1),    p2 = Promise.reject(2),    p3 = Promise.resolve(3);Promise.all([p1, p2, p3]).then(function (results) {    //then方法不会被执行    console.log(results);}).catch(function (e){    //catch方法将会被执行,输出结果为:2    console.log(2);});
Promise.all返回的是一个promise实例,所以我们手写的过程中也要返回一个promise,利用promise迷你书中实例化Promise的方法:
Promise.myall = function(promises){  return new Promise(fn)}
接下来我们再来处理promise数组promises,这里我们应该如何来获取promise实例变成fullfilled状态后的返回值呢?我们可以通过promise实例的then方法注册满足状态的回调函数,来获取满足状态的返回值。我们可以通过for循环的方式通过执行promise.then的方式来等待所有promise实例变化成resolve状态。此处还用到了闭包的知识点,在for循环中,如果i较小的promise居后返回了,在for的循环作用域中仍然可以记忆当时的i序号,返回主体为promise,结果数组变量在这个promise的构造过程中声明就好:
Promise.myall = function(promises){  return new Promise(function(resolve, reject){      let promiseNum = promises.length;      let resolvedValues = [];      for(let i = 0; i < promiseNum; i++){          promises[i].then(function(res){              resolvedValues[i] = res;            })        }    })}
接下来我们需要判断promise全部返回的时机,可以在for循环中通过结果i序号与输入promises数组长度对比来判断么?不可以,因为这样只要for循环完就会使我们的myall返回的promise变成fullfilled状态,不管所有异步promise是否都已经返回。所以我们可以把判断的逻辑放在每一个promise状态变成fullfilled的回调函数中来进行判断,这样就可以与promise真正变化状态的时机联系起来。但是如果还是判断序号i与promises长度还是不可以,因为如果最后一个promise先返回,那么依然会存在误判。所以我们通过序号i来判断并不准确,最准确的判断条件还是需要用在每一个promise状态变化之后的回调函数中来计数才比较安全:
Promise.myall = function(promises){  return new Promise(function(resolve, reject){      let promiseNum = promises.length;      let resolvedValues = [];        let resolvedCounter = 0;      for(let i = 0; i < promiseNum; i++){          promises[i].then(function(res){              resolvedCounter++;              resolvedValues[i] = res;                if (resolvedCounter == promiseNum) {                    return resolve(resolvedValues);                }            })        }    })}
下面我们还要考虑如果有一个promise变成rejected的状态,我们需要在promise构造函数的函数参数中调用reject的,很简单只需要在then的第二个参数来加上执行reject函数的逻辑即可:
Promise.myall = function(promises){  return new Promise(function(resolve, reject){      let promiseNum = promises.length;      let resolvedValues = [];        let resolvedCounter = 0;      for(let i = 0; i < promiseNum; i++){          promises[i].then(function(res){              resolvedCounter++;              resolvedValues[i] = res;                if (resolvedCounter == promiseNum) {                    return resolve(resolvedValues);                }            }, function(reason){              return reject(reason);            })        }    })}
至此一个基本的Promise.myall就实现好了,但是有的面试管这时还会来一个附加题: Promise.all是所有的promise同时开始执行,但是如果想让上一个promise执行完再执行下一个promise又该如何实现?   可能最先想到的是用await对上面的结果进行修改。但是我们也可以通过promise chain的方式来思考,下面是promise迷你书中介绍的一种方法:
function main(){  function recordValue(results, value){      results.push(value);        return results;    }    var pushValue = recordValue.bind(null, []);    var tasks = [promise1, promise2];    var promise = Promise.resolve();    for(let i = 0; i < tasks.length; i++){      var task = function(){          tasks[i].then((res)=>{              return res;            });        }        promise = promise.then(task).then(pushValue);    }    return promise;}main().then(function(value){  console.log(value);}).catch(function(error){  console.error(error);})
可以简单分析一下,摘抄下来的时候有一些改动。 首先再for循环前面通过Promise.resolve()来初始化一个fullfilled状态的promise实例,将需要迭代的每个promise放到了一个函数中,即为上一个promisefullfilled状态的回调函数,在回调函数中返回结果,经过promise迷你书中所述的then中回调函数返回值会经过Promise.resolve(返回值)包装,所以链式调用then时,会把返回的结果直接传入pushValue中,而pushValue处理完了上个结果后,会返回一个新的promise,下次迭代会基于这个新的已经fullfilled的promise直接执行满足状态的回调,最后返回的是所有promise数组返回的结果。

参考:

《JavaScript Promise 迷你书》

https://juejin.im/post/6844903509934997511

您是否也面临不知道自己在行业内技术水平如何,遇到的技能点由于长期没有再接触过容易忘记的问题呢?欢迎访问刷题小程序来解决上述两点问题,每月刷题最多的同学可以任选100元以内图书一本哦~

e430b2a4d1ccc40df291db3dc3e4da9e.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值