promise

栏目: JavaScript · 发布时间: 5年前

内容简介:## 前言今天来分享下promise的用法,es6伟大发明之一,当初我学习的时候也是蛮头大的,不知道为啥,整个脑子就是,我在哪,我要干啥的懵圈,后面认真学习之后,觉得真是十分好用,下面就来一起学习下吧。首先为什么会有promise的存在,其实很多人都知道的,其中最大的问题就是在处理多个有依赖关系的异步操作时,会出现回调地狱( callback hell ),如下:

## 前言

今天来分享下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 (<anonymous>: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
    });
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML5

HTML5

Matthew David / Focal Press / 2010-07-29 / USD 39.95

Implement the powerful new multimedia and interactive capabilities offered by HTML5, including style control tools, illustration tools, video, audio, and rich media solutions. Understand how HTML5 is ......一起来看看 《HTML5》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具