添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Promise的理解及react中的运用

Promise的理解及react中的运用

前言

前几天同事无意间问我对promise的理解,作为一年前端开发的我,虽然项目里一直有在用,但细细回想promise是什么、怎么用的和我对这个的理解,还真不说不出来,所以我周末就好好花了时间对promise进行了浅层的了解,如果有说错的欢迎指点。

一、promise是什么?为什么会有promise?

首先,promise是js的抽象异步处理对象实现异步编程的方案,简单的说就是解决传统js运行单线程的诟病以及异步操作的多层级嵌套带来的麻烦。

Q:资料说promise是个容器,我对这个理解不是很清晰。

我的理解是说,这个容器指promise的异步操作内容,然后我们这个操作放在这个容器里面让他自己执行,不会受外界影响。

然后,promise有三种状态,分别是:pending、fulfilled、rejected;
当 promise执行resolve是状态由pending->fulfilled;
当 promise执行reject是状态由pending->rejected;
状态一旦改变就不会再变。



二、基本用法

1、实例

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);

Promise对象是一个构造函数,实例后的Promise是一个对象,该构造函数接受一个函数参数,这个函数参数传入两个参数(resolve,reject), 这两个参数是各是一个函数方法;
我们可以根据函数的结果来判断执行resolve或reject;

2、.then()

promise.then(()=>{
   /* resolve 的执行内容 */
    },()=>{
    /*reject执行的内容*/

.then()方法接受两个函数参数,第一个参数是获取resolve的内容来执行异步操作,第二个参数是执行reject,然后执行一个捕获错误的内容,貌似可以获取代码执行错误的位置;
(我的理解:有then方法的promise才是完整的。)

2.1、第一个函数接受一个来自promise的构造函数resolve传递的对象;
3.2、第二个函数会不会promise构造函数的错误;

注意:建议是不推荐 .then(()=>{},()=>{/ 捕获错误 /}) 这样去捕获错误,而是推荐用.catch的方法去捕获错误 .then(()=>{/ resolve 内容 /}).catch(error){/ error捕获错误 /}。因为直接在后面点catch()就能够捕获第一次发生错误的地方。

运用promise做多层次的回调
终取到这个节点,但是如果用promise就能够同步异步操作去获取到;

console.log('start');
  var promise1 = new Promise((resolve,reject)=>{
              setTimeout(resolve('葡萄'),1);
  promise1.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',苹果'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',橘子'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',香蕉'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',西瓜'),1)))
          .then(value=>{console.log(value)});
  console.log('上面是个异步过程,所以我先出来,后面才是水果');
    控制台打印:
    start
    上面是个异步过程,所以我先出来,后面才是水果
    葡萄,苹果,橘子,香蕉,西瓜

这里的then都只执行了成功(resolve)方法,来把前面的只拼接起来传给下个then()方法去接受,下个then的value接受到上面的值继续new Promise 来执行下一个异步操作;

3、.all()

Promise.all() 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then() 方法。

// `delay`毫秒后执行resolve
  function timerPromisefy(delay) {
      return new Promise(function (resolve) {
         setTimeout(function () {
             resolve(delay);
         }, delay);
  var startDate = Date.now();
  // 所有promise变为resolve后程序退出
  Promise.all([
      timerPromisefy(1),
      timerPromisefy(32),
      timerPromisefy(64),
      timerPromisefy(128)
  ]).then(function (values) {
     console.log(Date.now() - startDate + 'ms');
      // 約128ms
     console.log(values);    // [1,32,64,128]

所以,promise.all,会在所有的参数里的Promise方法执行完再返回所有数据,以数组的格式。

4、.race()

Promise.race()的参数跟all一样是接受一个promise对象数组,不同的是race(),的结果是只要有一个promise变个fulfilled或rejected就能够then()中获取值,然后其他的Promise对象则会继续执行。

// `delay`毫秒后执行resolve
  function timerPromisefy(delay) {
     return new Promise(function (resolve) {
          setTimeout(function () {
            console.log(delay)
              resolve(delay);
          }, delay);
  // 任何一个promise变为resolve或reject 的话程序就停止运行
  Promise.race([
     timerPromisefy(1),
     timerPromisefy(32),
      timerPromisefy(64),
      timerPromisefy(128)
  ]).then(function (value) {
     console.log('then',value);    // => 1
  then,1 

三、在react中的运用

1、生命周期的运用

前几天有个需求是要在初次渲染完后获取页面的某个节点,但是我用了reactd的生命周期函数始终取到这个节点,但是如果用promise就能够同步异步操作去获取到;

componentWillMount() {
  let P = new Promise((resolve, reject)=>{
      console.log('new success')
      console.log('promiseNew',document.getElementById('text'))
      resolve('8888');
    P.then((value)=>{
      console.log('then','obj',document.getElementById('text'));
    .catch((error)=>{
      console.log('it is error',error)
  componentDidMount(){
    this.setState({isFind:true})
    console.log('DidMount',document.getElementById("text"))
  render() {
    return (
        {this.state.isFind ? (<Divider id="text">this is PromiseClick</Divider>) : null}
控制台打印内容:
  new success
  promiseNew null
  DidMount null
  then obj <div class="ant-divider ant-divider-horizontal ant-divider-with-text" id="text">…</div>

所以,我的认为是在react的生命周期函数里去执行promise的异步操作,相当于页面加载完再去执行的操作;

2、结合ajax请求的运用

前段时间,刚好有对登录调整的需求,这边登录会请求多个接口(用户信息、token、权限列表),所以之前就是用的多层的函数嵌套,在代码的排查上确实显得不那么直观,所以借此机会用了promise去做了一次代码重构。

一开是我以为NEW一个Promise实例出来,然后用return去传递返回的来的数据就可以了,如下:

错误示范

let P = new Promise((resolve, reject)=>{
      request.post(url, { form: reqBody, timeout: configObject.agTimeout }, function (error, response, body){
            if(!error) {
                resolve(body);
            } else {
                reject(error);
P.then(result=>{
  request.post(list.url1, { form: list.formData, timeout: configObject.agTimeout }, function (error, response, body) {
            if(!error){
            return body;//用return去传递返回的数据
            }else 
p.then(newResult => {
  console.log('newResult',newResult)
控制台打印内容:newResult ,undefined

原因

Promise异步加载,所以中间的那个ajax请求还没结束时,就会跑到.then里面。

其实,我之前也发现别人代码里每次请求都会重新去new一个Promise然后在构造函数里面去请求ajax,之前觉得这好麻烦,但经过这次实验,算是知道原因了,只有每次请求都去new一个Promise来请求,才能让逻辑按我们所想要的顺序去执行,同时每次请求可以判断成功与否,不成功只要把error传进reject中,就能够在最后面的catch中一起捕获。代码如下:

let P = new Promise((resolve, reject)=>{
     $.ajax({
        type:"get",
        url:"index.aspx",
        success:function(data){
            if(data.code=="0"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
P.then(result=>{
  return new Promise((resolve,reject) => {
    $.ajax({
        type:"get",
        url:"index.aspx2",
        success:function(data){
            if(data.code=="0"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
}).then((result) => {
  console.log('result',result)
}).catch((errot)=>{
  console.log('error',error)
控制台打印内容: