资讯专栏INFORMATION COLUMN

promise

jay_tian / 1938人阅读

摘要:是一个对象,它的内部其实有三种状态。已拒绝的异步操作未成功结束。方法则是将对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作。在第二个中拿到数据并且捕获。使用的写法比一般的写法更加清晰明确。

## 前言

今天来分享下promise的用法,es6伟大发明之一,当初我学习的时候也是蛮头大的,不知道为啥,整个脑子就是,我在哪,我要干啥的懵圈,后面认真学习之后,觉得真是十分好用,下面就来一起学习下吧。

为什么会有promise

首先为什么会有promise的存在,其实很多人都知道的,其中最大的问题就是在处理多个有依赖关系的异步操作时,会出现回调地狱( callback hell ),如下:

$.ajax({
      url: "....",
      success: function (data) {
            $.ajax({
                  url: "....",
                  success: function (data) {
              }
          });
      }
 });

promise提供了一个优雅的方式,来解决这个问题,同时提供了很多的错误捕获机制。

如何使用promise

我们先不讲promise的理论语法,这样会一开始就降低学习的欲望,直接来看使用案例,然后去理解。

首先看基本使用
new Promise(function (resolve, reject) {
         // 假设此处是异步请求某个数据
               $.ajax({
                  url: "......",
                   success: function (res) {
                       if (res.code === 200) {
                            resolve(res.data);
                        } else {
                           reject("获取data失败");
                      }
                   }
               })
})
.then(function A(data) {
        // 成功,下一步
      console.log( data);
 }, function B(error) {
        // 失败,做相应处理
       console.log(error)
 });
console:
sucess
error

解析:

梳理流程:

首先我们在promise函数里,执行我们的异步操作得到data

如果成功的话,通过resolve函数数据传递出来,如果失败。通过reject把错误信息传递出来

然后在.then里可以接受传递出来的数据,.then()里面接受两个函数,第一个函数接收resolve传递出来的值,也就是正确情况下的处理,第二个函数接收reject传递的信息,也就是错误的情况下的处理。

Promise是一个对象,它的内部其实有三种状态。

初始状态( pending )。

已完成( fulfilled ): Promise 的异步操作已结束成功。

已拒绝( rejected ): Promise 的异步操作未成功结束。

resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作。
reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作。

then(onFulfilled, onRejected)

---(onFulfilled, onRejected)

链式then

当然,我们既然解决回调地狱,一个异步,看不出来啥优势,现在看多个异步请求, 为了代码简约,我们用setTimeout来代替ajax请求 作为异步操作,如下:

new Promise((resolve, reject) => {
     setTimeout( () => {
          if (...){
            resolve([1, 2, 3])
        } else {
            reject("error");
        }
   }, 2000);
})
 .then( data => {
        console.log(value);  // 打印出[1, 2, 3]
        return new Promise( (resolve, reject)=> {   // 新的异步请求,需要promise对象
            let data2 = 1 + data;
            setTimeout( () => {
              if (...) {
                   resolve(data2);
              } else {
                  reject("error2")
              }
              
            }, 2000);
       });
  }, error => {
      cosnole.log(error)
  })
.then( data2 => {
      console.log(data2 );
 }, error => {
      cosnole.log(error)
  });
解析:

-这个例子中,第一个异步操作得到数据[1, 2, 3],传递到第一个then中,我们在第一个then中运用拿到的数据,进行第二次异步操作,并把结果传递出去。在第二个then中拿到数据,并且捕获error。
可以看到本来嵌套的两个异步操作,现在清晰多了,而且链式接无数个then

在这里有两个地方需要注意

then里面的可捕获错误的函数,可以捕获到上面的所有then的错误,所以只在最后一个then里,写错误捕获函数就可以。

每次异步操作时候需要返回一个新的promise,因为只有用promise对象才会等异步操作执行完,才去执行下面的then,才能拿到异步执行后的数据,所以第二个then里的异步请求,也需要声明Promise对象。如果then里面返回常量,可以直接返回。如下:

new Promise((resolve, reject) => {
     setTimeout( () => {
          if (...){
            resolve([1, 2, 3])
        } else {
            reject("error");
        }
   }, 2000);
})
 .then( value => {
        return "222";    // 如果是直接返回常量,可直接return
    })
 .then( value2 => {
     console.log(value2 ); // 打印出222
 })

下面忽略error情况,看两个例子,大家可以自己思考下打印结果

new Promise(resolve => {
    setTimeout( () => {
        resolve("value1");
    }, 2000);
})
 .then( value1 => {
        console.log(value1);
        (function () {
            return new Promise(resolve => {
                setTimeout(() => {
                    console.log("Mr.Laurence");
                    resolve("Merry Xmas");
                }, 2000);
            });
        }());
        return false;
    })
 .then( value => {
     console.log(value + " world");
 });

value1
false world
Mr.Laurence
new Promise( resolve => {
    console.log("Step 1");
    setTimeout(() => {
        resolve(100);
    }, 1000);
})
.then( value => {
     return new Promise(resolve => {
         console.log("Step 1-1");
         setTimeout(() => {
            resolve(110);
         }, 1000);
    })
    .then( value => {
           console.log("Step 1-2");
           return value;
    })
   .then( value => {
         console.log("Step 1-3");
         return value;
    });
})
.then(value => {
      console.log(value);
      console.log("Step 2");
});

console:
Step 1
Step 1-1
Step 1-2
Step 1-3
110
Step 2
catch

catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)。使用 catch 的写法比一般的写法更加清晰明确。我们在捕获错误的时候,直接在最后写catch函数即可。

 let promise = new Promise(function(resolve, reject) {
    throw new Error("Explosion!");
});
promise.catch(function(error) {
      console.log(error.message); // "Explosion!"
});

上面代码等于与下面的代码

 let promise = new Promise(function(resolve, reject) {
    throw new Error("Explosion!");
});
promise.catch(function(error) {
      console.log(error.message); // "Explosion!"
});
异步代码错误抛出要用reject
new Promise( resolve => {
    setTimeout( () => {
        throw new Error("bye");
    }, 2000);
})
.then( value => {
 })
.catch( error => {
      console.log( "catch", error);
 });
控制台会直接报错 Uncaught Error: bye

解析:因为异步情况下,catch已经执行完了,错误才抛出,所以无法捕获,所以要用reject,如下:

new Promise( (resolve, reject) => {
    setTimeout( () => {
        reject("bye");
    }, 2000);
})
.then( value => {
        console.log( value + " world");
 })
.catch( error => {
      console.log( "catch", error);
 });

catch bye
利用reject可以抓捕到promise里throw的错
catch 可以捕获then里丢出来的错,且按顺序只抓捕第一个没有被捕获的错误
new Promise( resolve => {
    setTimeout( () => {
        resolve();
    }, 2000);
})
.then( value => {
    throw new Error("bye");
 })
.then( value => {
   throw new Error("bye2");
 })
.catch( error => {
  console.log( "catch", error);
 });

console: Error: bye
new Promise( resolve => {
    setTimeout( () => {
        resolve();
    }, 2000);
})
.then( value => {
    throw new Error("bye");
 })
.catch( error => {
  console.log( "catch", error);
 })
.then( value => {
   throw new Error("bye2");
 })
.catch( error => {
  console.log( "catch", error);
 });

console: Error: bye
console: Error: bye2
catch 抓捕到的是第一个没有被捕获的错误
错误被捕获后,下面代码可以继续执行
new Promise(resolve => {
    setTimeout(() => {
        resolve();
    }, 1000);
})
    .then( () => {
        throw new Error("test1 error");
    })
    .catch( err => {
        console.log("I catch:", err);   // 此处捕获了 "test1 error",当错误被捕获后,下面代码可以继续执行
    })
    .then( () => {
        console.log(" here");
    })
    .then( () => {
        console.log("and here");
         throw new Error("test2 error");
    })
    .catch( err => {
        console.log("No, I catch:", err);  // 此处捕获了 "test2 error"
    });

I catch: Error: test2 error
here
and here
 I catch: Error: test2 error
错误在捕获之前的代码不会执行
new Promise(resolve => {
    setTimeout(() => {
        resolve();
    }, 1000);
})
    .then( () => {
        throw new Error("test1 error");
    })
    .catch( err => {
       console.log("I catch:", err);   // 此处捕获了 "test1 error",不影响下面的代码执行
       throw new Error("another error"); // 在catch里面丢出错误,会直接跳到下一个能被捕获的地方。
    })
    .then( () => {
        console.log("and here");
         throw new Error("test2 error");
    })
    .catch( err => {
        console.log("No, I catch:", err);  // 此处捕获了 "test2 error"
    });

I catch: Error: test2 error
I catch: Error: another error
new Promise(resolve => {
    setTimeout(() => {
        resolve();
    }, 1000);
})
    .then( () => {
        console.log("start");
        throw new Error("test1 error");
    })
    .then( () => {
        console.log("arrive here");
    })
    .then( () => {
        console.log("... and here");
         throw new Error("test2 error");  
    })
    .catch( err => {
        console.log("No, I catch:", err);   // 捕获到了第一个
    });

No, I catch: Error: test1 error
    at Promise.then (:8:1
Promise.all
Promise.all([1, 2, 3])
      .then( all => {
          console.log("1:", all);
      })
[1, 2, 3]
Promise.all([function () {console.log("ooxx");}, "xxoo", false])
      .then( all => {
         console.log( all);
      });
 [ƒ, "xxoo", false]
let p1 = new Promise( resolve => {
            setTimeout(() => {
                resolve("I"m P1");
            }, 1500);
});
let p2 = new Promise( (resolve, reject) => {
            setTimeout(() => {
                resolve("I"m P2");
            }, 1000);
 });
let p3 = new Promise( (resolve, reject) => {
            setTimeout(() => {
                resolve("I"m P3");
            }, 3000);
 });

 Promise.all([p1, p2, p3]).then( all => {
       console.log("all", all);
}).catch( err => {
        console.log("Catch:", err);
});

all (3) ["I"m P1", "I"m P2", "I"m P3"]
案例:删除所有数据后,做一些事情、、、、
db.allDocs({include_docs: true}).then(function (result) {
  return Promise.all(result.rows.map(function (row) {
    return db.remove(row.doc);
  }));
}).then(function (arrayOfResults) {
  // All docs have really been removed() now!
});
Promise.resolve
Promise.resolve()
    .then( () => {
        console.log("Step 1");
    })
其他
Promise.resolve("foo").then(Promise.resolve("bar")).then(function (result) {
  console.log(result);
});
VM95:2 foo
如果你向 then() 传递的并非是一个函数(比如 promise)
它实际上会将其解释为 then(null),这就会导致前一个 promise 的结果会穿透下面
How do I gain access to resultA here?
function getExample() {
    return promiseA(…).then(function(resultA) {
        // Some processing
        return promiseB(…);
    }).then(function(resultB) {
        // More processing
        return // How do I gain access to resultA here?
    });
}
解决 Break the chain
function getExample() {
    var a = promiseA(…);
    var b = a.then(function(resultA) {
        // some processing
        return promiseB(…);
    });
    return Promise.all([a, b]).then(function([resultA, resultB]) {
        // more processing
        return // something using both resultA and resultB
    });
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102205.html

相关文章

  • Promise的几个扩展API总结

    摘要:的几个扩展总结描述和相反,当所有的被拒绝之后,方法执行完成的决议,如果存在一个执行完成的决议,方法则执行拒绝里边的所有实例反过来就好了执行到此执行到此描述忽略被拒绝的,只需要有一个完成的,方法就执行完成操作,如果全部的都被拒绝,方法执行拒绝 Promise的几个扩展API总结 1. Promise.none 描述: 和 Promise.all 相反,当所有的promise被拒绝之后,n...

    李义 评论0 收藏0
  • Promise 中的三兄弟 .all(), .race(), .allSettled()

    摘要:对于的来说基元函数包括组合函数的类型签名返回情况完成如果传入的可迭代对象为空,会同步地返回一个已完成状态的。相反,如果是在指定的时间之后完成,刚返回结果就是一个拒绝状态的从而触发方法指定的回调函数。在行中,对每个小任务得到的结果进行汇总。 为了保证的可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 从ES6 开始,我们大都使用的是 P...

    vspiders 评论0 收藏0
  • 异步发展流程 —— 手写一个符合 Promise/A+ 规范的 Promise

    摘要:构造函数的实现我们在使用的时候其实是使用关键字创建了一个的实例,其实是一个类,即构造函数,下面来实现构造函数。 showImg(https://segmentfault.com/img/remote/1460000018998456); 阅读原文 概述 Promise 是 js 异步编程的一种解决方案,避免了 回调地狱 给编程带来的麻烦,在 ES6 中成为了标准,这篇文章重点不是叙...

    UnixAgain 评论0 收藏0
  • 实现Promise

    摘要:使用是极好的,它是如此有用以至于我觉得应该好好研究一下,甚至是实现一个简易的版本。构造函数检查参数例如是不是函数啊初始化,创建对象执行因此构造函数里面传入的是立即被执行的。 使用Promise是极好的,它是如此有用以至于我觉得应该好好研究一下Promise,甚至是实现一个简易的版本。实现之前,我们先来看看Promise的用途: 使用Promise callback hell Promi...

    xcc3641 评论0 收藏0
  • Promise 对象的理解

    摘要:使用对象的好处在于可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。对象异步操作抛出错误,状态就会变为,就会调用方法指定的回调函数处理这个错误。 Promise 含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。 所谓 P...

    church 评论0 收藏0
  • Promise的源码实现(完美符合Promise/A+规范)

    摘要:以上代码,可以完美通过所有用例。在的函数中,为何需要这个同样是因为规范中明确表示因此我们需要这样的来确保只会执行一次。其他情况,直接返回以该值为成功状态的对象。 Promise是前端面试中的高频问题,我作为面试官的时候,问Promise的概率超过90%,据我所知,大多数公司,都会问一些关于Promise的问题。如果你能根据PromiseA+的规范,写出符合规范的源码,那么我想,对于面试...

    gaomysion 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<