浅谈Promise对象在ReactNative中的使用

写在前面

假设现在一个日常开发会遇到这样一个需求:多个接口异步请求,第二个接口依赖于第一个接口执行完毕之后才能利用数据进行一系列操作。一般会这样写:

            A.fetchData({
                url: 'http://......',
                success: function (data) {
                    A.fetchData({
                        // 要在第一个请求成功后才可以执行下一步
                        url: 'http://......',
                        success: function (data) {
                             // ......
                        }
                    });
                }
            });

这样写没问题,但是有两个缺点:
1、当有多个操作的时候,会导致多个回调函数嵌套,不够美观
2、如果有几个操作没有前后顺序之分时,例如上面的后一个请求不依赖与前一个请求的返回结果的时候,同样也需要等待上一个操作完成再实行下一个操作。

从ES6开始,Promise对象可以解决上述问题。

什么是Promise对象

一个Promise对象可以理解为一次将要执行的操作,使用了Promise对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。

resolve和reject

先看代码:

  function helloWorld (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello World!");
        } else {
            reject("Good bye!");
        }
    });
  }

    helloWorld(true).then(function (message) {
        alert(message);
    }, function (error) {
        alert(error);
    });

上面的代码实现的功能非常简单,helloWord 函数接受一个参数,如果为 true 就打印 "Hello World!",如果为 false 就打印错误的信息。helloWord 函数返回的是一个 Promise 对象。

在 Promise 对象当中有两个重要方法————resolve 和 reject。

resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作,在这个例子当中就是 Hello World! 字符串。

reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作。

then

Promise 对象有三种状态:
1.Fulfilled 可以理解为成功的状态
2.Rejected 可以理解为失败的状态
3.Pending 既不是 Fulfilld 也不是 Rejected 的状态,可以理解为 Promise 对象实例创建时候的初始状态。

helloWorld 的例子中的 then方法就是根据 Promise 对象的状态来确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)。promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS Promise/A 标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler, rejectedHandler); 。resolvedHandler 回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。

示例代码1:

function printHello (ready) {
  var promise = new Promise(function (resolve, reject) {
      if (ready) {
          resolve("Hello");
      } else {
          reject("Good bye");
      }
  });
  return promise;
}

function printWorld () {
    console.log('World');
}

function printExclamation () {
    console.log('!!!');
}

 printHello(true)
 .then(function(message)
 .then(printWorld)
 .then(printExclamation)
 .catch(function(error){
    console.log(error);
  });;

函数先执行printHello,返回一个promise对象,通过then将异步操作串联起来。
执行结果应该是 Hello
World
!!!

示例代码2:

  function helloWorld (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello World!");
        } else {
            reject("Good bye!");
        }
    });
  }

  var _this = this;
  printHello(true)
  .then(function (message) {
  var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
   return  fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        var movie = responseData.movies[1];
        console.log('data   =   ', movie.title);
        return movie.title;
      })
  },function (error) {
      return(error);
  }).then(function (message) {
      return message  + ' World';
  }).then(function (message) {
      return message + '!!!';
  }).then(function (message) {
     console.log(message);
     console.log('finally');
  }).catch(function(error){
     console.log(error);
  });

上面的代码中有两个promise,第一个promise执行完毕后也就是printHello之后,会执行下一个then,这个then返回了一个获取数据的promise,后面的then拿到的promise都是指向这个promise对象的。上述例子通过链式调用的方式,按顺序打印出了相应的内容。then 可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个 Promise 对象。另外,在 then onFulfilled 的函数当中的返回值,可以作为后续操作的参数。

catch

catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)。使用 catch 的写法比一般的写法更加清晰明确。

新手使用容易犯的错误

1.忘记添加catch()方法

这是一个很常见的错误。很多程序员对他们代码中的promise调用十分自信,觉得代码永远不会抛出一个 error ,也可能他们只是简单的忘了加 catch() 方法。不幸的是,不加 catch() 方法会让回调函数中抛出的异常被吞噬,在你的控制台是看不到相应的错误的,这对调试来说是非常痛苦的。

为了避免这种糟糕的情况,我已经养成了在自己的promise调用链最后添加如下代码的习惯:

      somePromise().then(function () {
        return aPromise();
      }).then(function () {
        return anotherPromise();
      }).catch(function(error){
               console.log(error);
            });

即使你并不打算在代码中处理异常,在代码中添加 catch() 也是一个谨慎的编程风格的体现。在某种情况下你原先的假设出错的时候,这会让你的调试工作轻松一些。

2.return的混淆乱用

在then方法内部,我们可以做三件事:
1.return 一个promise对象
2.return一个同步的值或者是 undefined
3.同步的 throw 一个错误

理解这三种情况之后,你就会理解promise了。

1.返回另一个promise对象

在有关promise的相关文章中,这种写法很常见,就像上文提到的构成promise链的一段代码:

        getUserByName('nolan').then(function (user) {
            
          return fetch(REQUEST_URL)
                .then((response) => response.json())
                .then((responseData) => {
         
                 }      
                        
        }).then(function () {
        });

2.返回一个具体的值或者是 undefined

    getUserByName('nolan').then(fcuntion (user) {
        if (inMemoryCache[user.id]) {
            return inMemoryCache[user.id];  
            // returning a value!
        }
        return inMemoryCache[user.id];
         // returning a promise
    }).then(function (userAccount) {
        // I got a user account
    })

如果不调用return语句的话,javaScript里的函数会返回 undefined 。这也就意味着在你想返回一些值的时候,不显式调用return会产生一些副作用。

出于上述原因,养成了一个个人习惯就是在then方法内部永远显式的调用return或者throw。我也推荐你这样做。

3.抛出一个错误

说到throw,这又体现了promise的功能强大。在用户退出的情况下,我们的代码中会采用抛出异常的方式进行处理:

    getUserByName('nolan').then(function (user) {
      if (user.isLoggedOut()) {
        throw new Error('user logged out!'); 
        // throwing a error!
      }
      if (inMemoryCache[user.id]) {
        return inMemoryCache[user.id];      
         // returning a value!
      }
      return getUserAccountById(user.id);   
       // returning a promise!
    }).then(function (userAccount) {
      // I got a user account!
    }).catch(function (err) {
      // Boo, I got an error!
    });

如果用户已经登出的话, catch() 会收到一个错误,如果有promise对象的状态变为rejected的话,它还会收到一个错误。
在使用promise的时候抛出异常在开发阶段很有用,它能帮助我们定位代码中的错误。比方说,在then函数内部调用 JSON.parse() ,如果JSON对象不合法的话,可能会抛出异常,在回调函数中,这个异常会被吞噬,但是在使用promise之后,我们就可以捕获到这个异常了。

微博账号:梅嘉庆(点击关注)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 00、前言Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区...
    夜幕小草阅读 2,126评论 0 12
  • 本文适用的读者 本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,...
    HZ充电大喵阅读 7,293评论 6 19
  • Promise的含义:   Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和...
    呼呼哥阅读 2,158评论 0 16
  • Promiese 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,语法上说,Pr...
    雨飞飞雨阅读 3,348评论 0 19
  • 微信oauth前后端分离实现 在前后端分离的基础上,实现微信的oauth机制 如何获取微信用户信息 页面如果需要获...
    nothingp阅读 3,684评论 0 1