博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
promise
阅读量:5739 次
发布时间:2019-06-18

本文共 9291 字,大约阅读时间需要 30 分钟。

## 前言

今天来分享下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:sucesserror

解析:

梳理流程:
  • 首先我们在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'); });value1false worldMr.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 1Step 1-1Step 1-2Step 1-3110Step 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: byeconsole: Error: bye2catch 抓捕到的是第一个没有被捕获的错误
错误被捕获后,下面代码可以继续执行
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 errorhereand 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 errorI 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    });}

转载地址:http://axfzx.baihongyu.com/

你可能感兴趣的文章
mysql 行转列列转行
查看>>
《设计模式系列》---桥接模式
查看>>
[Unity3d]Shader 着色器 学习前了解知识
查看>>
Redrain duilib中事件委托存在的问题
查看>>
字符串的简单操作
查看>>
C#新功能--命名参数与可选参数
查看>>
strtok和strtok_r
查看>>
维辰超市:借助云商城成功转型新零售
查看>>
web.xml中<load-on-start>n</load-on-satrt>作用
查看>>
【算法】CRF
查看>>
windows 8 微软拼音输入法
查看>>
Windows UI风格的设计(7)
查看>>
SQL中使用WITH AS提高性能 使用公用表表达式(CTE)简化嵌套SQL
查看>>
oracle 强行杀掉一个用户连接
查看>>
Git提交本地库代码到远程服务器的操作
查看>>
mysql中主外键关系
查看>>
我的友情链接
查看>>
让你快速上手的Glide4.x教程
查看>>
浮动和清除(闭合)浮动
查看>>
微信小程序注册流程
查看>>