实用主义:Promise让异步回调更加优雅

前言

函数作为一等对象,使得javascript这种弱类型,单线程脚本语言的异步方法极为方便,只需要一个callback,编译器就能按照我们的想法执行命令。如果只有一个简单的异步操作,我们可以稍费脑子理清执行顺序,但是如果有多个异步方法,呃,我们就可能掉进了回调陷阱,事情远远没有我们想到的那么简单,并且我们甚至还没考虑过异步中抛出的错误。

还好Promise的出现,解救了我们,这篇文章不是讲解Promise的详细使用方法,只是通过两个例子,看看Promise的优雅之处,详细资料请参考阮一峰老师 《ES6标准入门》

传统的ajax回调

代码运行于最新的Chrome版本中,Chrome目前已支持除 模块 以外的大部分ES6方法

let xhr = new XMLHttpRequest();
    let url = 'http://chat.hstar.org:8601/rkyNA2Yvl/promise';
    xhr.responseType = "text";
    xhr.open('get', url, true);
    xhr.onreadystatechange = ((data) => {
        if (xhr.readyState===4 && xhr.status===200) {
                let data = JSON.parse(xhr,responseText);
                console.log(data.word);
        }
    });
    xhr.send(null);

结果

这是一个传统的ajax回调,我们把所有事务逻辑封装在onreadystatechange事件中,并且xhr的生成与使用都在一块代码内。后期的维护、DOM操作都只能该事件中进行,这只是一个异步事件,如果是多个异步事件,并且需要所有事件都能完成才能操作。Oh my god。我们可能已经进入回调地狱。这团代码在后期debug时候足以让我们抓狂。

Promise的出现

我们再来看看一段经过Promise封装的代码

function getPromise(url) {
        let p = new Promise((resolve,reject) => {
          let xhr = new XMLHttpRequest;
          xhr.open('get', url, true);
          xhr.onreadystatechange = () => {
            if (xhr.status == 200 && xhr.readyState===4 ){
                resolve(xhr.responseText);
                }   
            };
            xhr.onerr = function () {
                    reject();
            }
            xhr.send(null);
        });
        return p;
}

首先封装一个Promise对象,我们把响应事件封装在resolve方法中,如果仅仅是这样,那么和普通封装没有区别,我们接着来看看Promise的优雅之处

let promise = getPromise('http://chat.hstar.org:8601/rkyNA2Yvl/promise');
    promise.
    then(data => {
        data = JSON.parse(data);
        return data;
    }).then(data => {
        document.write(data.word);
        console.log(data);
    }).catch(err => {
        console.log(err);
    });

结果

我们通过then(resolve方法的别名),进行回调操作,then方法返回的也是一个Promise对象,因此可以链式调用,这样我们可以按步骤操作返回的数据。并且catch方法会捕捉每一个异步方法中的错误,所有的错误都会冒泡到这里,如果catch方法出现了错误怎么办?别担心done()方法会处理最后的错误。 通过这样的链式调用,使得 关注点 分离,return的形式也更符合人脑的思考逻辑。 前面还提到了多个异步操作,我们同样可以使用Promise.all和Promise.race方法。

最后

相比传统的ajax方法,Promise的优雅之处在于

  1. 关注点分离,每一次调用只需要完成一个任务;
  2. 更符合人脑思考逻辑;
  3. 良好的错误处理逻辑,错误冒泡;
  4. all() 和 race()方法避免陷入回调地狱

这里仅仅是简单封装了XMLHttpRequest方法,随着JS的发展,fetch axios vue-resource等新一代ajax方法都已经实现了对Promise的封装,这里也该大家分享一段我们项目对Promise的深度封装实现(基于axios)

基于axios的封装

所以大家也快来拥抱ES6的新特性吧 就是这样:)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博文

js中判断浏览器版本

var ai = { ovb: { /** * 该对象用于判断系统,系统版本,浏览器,...

4995
来自专栏酷玩时刻

微信扫码支付(模式一)微信扫码支付(模式一)

官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4

1973
来自专栏Golang语言社区

Node.js新手必须知道的4个JavaScript概念

如果只需要知道一种编程语言就可以构建一个全栈的应用程序,是不是特别了不起?Ryan Dahl为了把这个想法成为现实,创造了node.js。Node.js是建立在...

3387
来自专栏Java帮帮-微信公众号-技术文章全总结

【Java提高十四】异常

Java的基本理念是“结构不佳的代码不能运行”!!!!! 大成若缺,其用不弊。 大盈若冲,其用不穷。 在这个世界不可能存在完美的东西,不...

3414
来自专栏技术栈大杂烩

Python: 受限制的 "函数调用"

函数功能简单明了, 对于结果, 大家应该也不会有太大的异议:func分别是取得全局命名空间中a的值和使用内置命名空间中的函数id获取了a的地址. 熟悉Pytho...

1503
来自专栏猿人谷

C++内存管理学习堆和栈

一 C++内存管理 1.内存分配方式   在讲解内存分配之前,首先,要了解程序在内存中都有什么区域,然后再详细分析各种分配方式。 1.1 C语言和C++内存分...

3356
来自专栏web前端教室

复习知识点 -- JS高效拼接字符串

image.png JS拼接字符串,一种是用变量 += ,另一种是用 join。这个办法我早就知道,但一直用的不是很熟练,今天就复习一下。 第一是js的字符...

29310
来自专栏Golang语言社区

Node.js新手必须知道的4个JavaScript概念

如果只需要知道一种编程语言就可以构建一个全栈的应用程序,是不是特别了不起?Ryan Dahl为了把这个想法成为现实,创造了node.js。Node.js是建立在...

2964
来自专栏平凡文摘

JDK 10 的 109 项新特性

1042
来自专栏宋凯伦的技术小栈

分享调用Java private方法

上周在修复bug时,发现Java类中某方法是private,且类中没有用到,第一感觉是方法多余。其实通过分析,发现原来Native Code会通过JNI调到此方...

2165

扫码关注云+社区

领取腾讯云代金券