Promise对象探究

一、简介


Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。

以上定义引自阮一峰《Javascript异步编程的4种方法》。

我的简单理解是,Promise是JavaScript异步回调的解决方案之一,最大的优点是以链式调用的方式来消除Callback Hell的问题。


二、用法


1、运用一个Promise对象可以总结成两个步骤:
  1. 异步。决定回调的时机(when)。
  2. 回调。实现回调的内容(what)。

举个栗子,通常网络模块的业务逻辑是:请求数据、解析返回的数据并显示。为了代码写起来简单一点,这里抽象成“进行耗时操作(比如timeout个3秒)、显示数据”。
在这里,“异步”就是耗时操作的过程:

// 定义一个Promise对象,通过new Promise的方式
// 参数是待定的。resolveCallback是成功的回调,rejectCallback是失败的回调
// resolveCallback和rejectCallback,只有其中一个会被执行

var promise = new Promise(function (resolveCallback, rejectCallback) {
    setTimeout(function () {
        resolveCallback("this is the returned data.");
    }, 3000);
});

“回调”就是之后的把数据显示在View上的过程:

// 用then,参数是两个回调函数的实现:一个成功的回调,一个失败的回调

promise
    .then(function (data) {
        console.log(data); // 成功的具体的回调,把data显示在界面上
    }, function (error) {
        console.log(error); // 失败的具体回调
    })


2、优点:链式调用

因为每次使用then,会返回Promise对象本身,而这个Promise对象又有then方法,所以可以一直调用下去,称之为“链式调用”。这也是Promise最大的优点,我们通常说它“更优雅的异步回调”,是因为它解决了Callback Hell的问题。链式调用最关键的地方在于,后一个then的回调参数,是前一个then的回调中的返回值,就像这样:

// 异步过程
var promise = new Promise(function (resolveCallback, rejectCallback) {
    setTimeout(function () {
        resolveCallback("this is the returned data.");
    }, 2000);
});

// 回调过程
promise

    .then(function (data) {
        console.log(data);
        return data + "again."; //return是给下一个then的参数。缺少就是undefined
    }, function (error) {
        console.log(error);
    })

    .then(function (data) { // 这里接收到上一个then给的参数
        console.log(data);
    }, function (error) {
        console.log(error);
    });
    // 可以无限then下去……

结果截图:
这里写图片描述


三、对比


1、与Android中接口回调的联系:

上面说到的两个步骤,“异步”和“回调”,很容易让人联想到Android中类似的做法。在Android SDK代码中,如果想要进行网球请求的异步回调,通常的做法是定义一个interface来作为回调的媒介,在这个接口中,至少含有请求成功、失败的回调。

// 定义网络请求回调的统一接口

public interface NetworkCallback {

    void onSuccess(String response); //成功的回调,待实现

    void onError(String error);      //失败的回调,待实现
}

注意,以下代码是为了简便而简写,可能有错误的地方,比如一些try catch就暂时省略。

// 异步请求。决定回调的时机。
// 假定该文件是NetworkHelper.class

public void get(String url, NetworkCallback cb) {
    HttpUrlConnection conn = (HttpUrlConnection) new URL(url).openConnection();
    if (conn.getStatusCode() == 200) { // 如果请求OK
        String data;
        //...get data from InputStream
        cb.onSuccess(data);     // 回调成功的函数
    } else {
        cb.onError("Error..."); // 回调失败的函数
    }
}
// 回调。实现回调的内容,也就是实现上面定义的接口。

NetworkHelper.get("http://www.google.com", new NetworkCallback() {

    @Override
    public void onSuccess(String response) {
        // 处理、显示返回的结果
    }

    @Override
    public void onError(String error) {
        // 处理错误
    }
});

可见,Android中的异步回调的这种做法,跟Promise的使用过程是很相似的,因为思想是一样的,就是异步+回调。不过,Promise自身多了一个链式调用的优点。


2、与NodeJS中经典的异步API的比较:

NodeJS本身提供了许多异步的“错误优先”的API,比如一个读取文件的函数readFile,假如我想要读取文件完毕之后,打印出一句话“Done!”,那一般的做法是:

var fs = require('fs');

function read(uri) {
    fs.readFile(uri, function (err, data) {
        if (!err) {
            console.log('Done!');
            // 这里可能还会有更多异步操作,就会造成Callback Hell
        } else {

        }
    });
}

为了避免Callback Hell,我们可以把它封装成一个Promise对象:

var fs = require('fs');

function read(uri) {
    return new Promise(function (resolve, reject) {

        fs.readFile(uri, function (err, data) {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });

    });
}

read('./../images/test.png')

    .then(function (data) {
        console.log('length of file1:', data.toString().length);
        return read('./hello.js');  // 这里返回一个promise对象以链式调用
    }, function (err) {
        console.log(err);
    })

    .then(function (data) {
        console.log('length of file2:', data.toString().length)
    }, function (err) {
        console.log(err);
    });

效果:
这里写图片描述

如果想要深入了解链式调用的封装效果,推荐这篇博客:http://swiftcafe.io/2016/07/27/updator/


3、与RxJava(RxAndroid)的类比:

把嵌套回调写成链式,除了Promise,还有RxJava。不过在这里就不详细展开了,就大致列一下它们之间相同和不同的地方吧。

相同点:
  • 链式解决Callback Hell。
不同点:
  • RxJava是面向数据流的,将数据封装成特有的类型“Observable”;并且,提供对Observable的一系列便捷的操作,即函数式编程。而Promise没有对数据的更进一步的封装。
  • RxJava可以方便地在线程之间切换,实现更高权限的控制。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值