89500297 2020-04-11
1.面试题
2.
在 Promise 出现以前,我们处理一个异步网络请求,大概是这样:
// 请求 代表 一个异步网络调用。 // 请求结果 代表网络请求的响应。 请求1(function(请求结果1){ 处理请求结果1 }) 复制代码
看起来还不错。
但是,需求变化了,我们需要根据第一个网络请求的结果,再去执行第二个网络请求,代码大概如下:
请求1(function(请求结果1){ 请求2(function(请求结果2){ 处理请求结果2 }) }) 复制代码
看起来也不复杂。
但是。。需求是永无止境的,于是乎出现了如下的代码:
请求1(function(请求结果1){ 请求2(function(请求结果2){ 请求3(function(请求结果3){ 请求4(function(请求结果4){ 请求5(function(请求结果5){ 请求6(function(请求结果3){ ... }) }) }) }) }) }) 复制代码
这回傻眼了。。。 臭名昭著的 回调地狱 现身了。
更糟糕的是,我们基本上还要对每次请求的结果进行一些处理,代码会更加臃肿,在一个团队中,代码 review 以及后续的维护将会是一个很痛苦的过程。
回调地狱带来的负面作用有以下几点:
出现了问题,自然就会有人去想办法。这时,就有人思考了,能不能用一种更加友好的代码组织方式,解决异步嵌套的问题。
let 请求结果1 = 请求1(); let 请求结果2 = 请求2(请求结果1); let 请求结果3 = 请求3(请求结果2); let 请求结果4 = 请求2(请求结果3); let 请求结果5 = 请求3(请求结果4); 复制代码
类似上面这种同步的写法。 于是 Promise 规范诞生了,并且在业界有了很多实现来解决回调地狱的痛点。比如业界著名的 Q 和 bluebird,bluebird 甚至号称运行最快的类库。
Promise 这么多概念,初学者很难一下子消化掉,那么我们可以采取强制记忆法,强迫自己去记住使用过程。
首先初始化一个 Promise 对象,可以通过两种方式创建, 这两种方式都会返回一个 Promise 对象。
然后调用上一步返回的 promise 对象的 then 方法,注册回调函数。
new Promise(fn) .then(fn1(value){ //处理value }) 复制代码
最后注册 catch 异常处理函数,处理前面回调中可能抛出的异常。
通常按照这三个步骤,你就能够应对绝大部分的异步处理场景。用熟之后,再去研究 Promise 各个函数更深层次的原理以及使用方式即可。