前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Promise的all和race方法的使用

Promise的all和race方法的使用

作者头像
挥刀北上
发布2019-08-06 16:13:22
1K0
发布2019-08-06 16:13:22
举报
文章被收录于专栏:Node.js开发

前文初识Promise中,可以初步了解Promise的简单用法和作用。今天这篇将更进一步,重点介绍promise的两个方法——all和race

先由一个例子引入,仔细观察以下腾讯新闻的页面。

页面上的列表非常多,来看一下network控制面板的情况:

可以看到,这些列表数据不是后端一次请求全部返回给前端的,而是不同的接口,返回不同的列表。页面一加载,就发送了一系列jsonp的请求。

思考一下:页面一下子发送这么多的jsonp请求,如何能得到所有的数据后一起处理呢?

假如页面中发送了四个请求,看以下代码:

代码语言:javascript
复制
$.get("https://cnodejs.org/api/v1/topics?tab=good",function(data){
    console.log(data);

    });
$.get("https://cnodejs.org/api/v1/topics?tab=job",function(data){
    console.log(data);
  
    });
$.get("https://cnodejs.org/api/v1/topics?tab=share",function(data){
    console.log(data);
  
    });
$.get("https://cnodejs.org/api/v1/topics?tab=ask",function(data){
    console.log(data);
    });

不难发现,页面中每个ajax的回调都是一个独立的作用域。这样看来,将四个data组合在一起貌似不太可能,有人可能会定义一个全局数组变量和一个定时器,写出如下代码:

代码语言:javascript
复制
var arr = []
$.get("https://cnodejs.org/api/v1/topics?tab=good", function (data) {
    arr.push(data)
    console.log(data);
});
$.get("https://cnodejs.org/api/v1/topics?tab=job", function (data) {
    arr.push(data)
    console.log(data);

});
$.get("https://cnodejs.org/api/v1/topics?tab=share", function (data) {
    arr.push(data)
    console.log(data);

});
$.get("https://cnodejs.org/api/v1/topics?tab=ask", function (data) {
    arr.push(data)
    console.log(data);
});
setTimeout(function () {
    console.log(arr);
}, 1500)

运行后,这段代码有时候可能会成功,有时候会失败,究其原因就是请求的回调函数返回的时间不确定。

这种方法不行,那再试着用回调嵌套回调来解决看看:

代码语言:javascript
复制
$.get("https://cnodejs.org/api/v1/topics?tab=ask", function (data) {
    arr.push(data);
    $.get("https://cnodejs.org/api/v1/topics?tab=job", function (data) {
        arr.push(data);
        $.get("https://cnodejs.org/api/v1/topics?tab=good", function (data) {
            arr.push(data);
            $.get("https://cnodejs.org/api/v1/topics?tab=share", function (data) {
                arr.push(data);
                console.log(arr)
            })
        })

    })
})

这种方法同时拿到了所有回调的数据,并进行处理。但是,咱们看看network的控制面板吧:

看下总时间和waterfall,花的时间是四次ajax的时间的总和!!这简直是对宝贵时间的巨大浪费有木有!!

那么,有没有四个ajax同时发送请求又可以在同一个作用域操作数据的方式呢?

当然有了,看代码:

代码语言:javascript
复制
var count = 0;
var arr = [];
function handle() {
    if (count === 4) {
        console.log(arr);
    }
}
$.get("https://cnodejs.org/api/v1/topics?tab=good", function (data) {
    arr.push(data);
    count++;
    handle()
})
$.get("https://cnodejs.org/api/v1/topics?tab=job", function (data) {
    arr.push(data);
    count++;
    handle()
})
$.get("https://cnodejs.org/api/v1/topics?tab=share", function (data) {
    arr.push(data);
    count++;
    handle()
});
$.get("https://cnodejs.org/api/v1/topics?tab=ask", function (data) {
    arr.push(data);
    count++;
    handle()
});

此时的思路是这样的:定义一个全局数组,一个计数器变量,一个检查器函数。每次回调执行,计数器都会加1,并把数据塞进数组,并且会执行检查器函数,当检查器满足条件时,证明所有数据返回,并且数据都保存到了一个数组里,可以对其进行操作了。

这时再来看network,寻找一下成就感。

可以明显感觉到:时间变短了,而且是并发发送。相比上面的回调嵌套,节省了很多时间。

貌似问题是解决了,但再回头审视一下这段代码,会发现这种处理方式,增加了额外的计数器变量count,额外的全局数组,额外的检查器函数。代码量的激增,无形中增加了后续维护的压力。如何能更轻松地实现同样的效果呢?

这时就需要出动Promise的all方法了。

代码语言:javascript
复制
// 封装一个promise;
var p = function (url) {
    return new Promise(function (resolve, reject) {

        $.get(url, function (data) {
            resolve(data);

        })
    })
}
Promise.all([
    p("https://cnodejs.org/api/v1/topics?tab=good"),
    p("https://cnodejs.org/api/v1/topics?tab=share"),
    p("https://cnodejs.org/api/v1/topics?tab=ask"),
    p("https://cnodejs.org/api/v1/topics?tab=job")
]).then(function (results) {
    console.log(results);
})

还是通过看network:

可以发现:同样是并发请求,Promise的all方法的参数是一个数组,数组每一项其实就是一个promise对象,每个promise对象内部都会resolve一团数据,这团数据会被之后的then方法接收,then方法接收到的数据也是一个数组,正好对应all方法里面每个promise对象resolve出来的数据。

没有全局数组,没有计数器变量,没有检查器函数。是不是很赞?

接着来介绍同样很酷炫的race方法

和前面一样,先从讨论一个需求入手:在页面上发送了一个ajax请求,如果1000ms内没有返回就进行默认的操作。

用最传统的方式如何实现以上需求?如下:

代码语言:javascript
复制
var ajax = $.get("https://cnodejs.org/api/v1/topics?tab=good",function(data){
  console.log(data);
  console.log("数据返回,清除定时器");
  clearTimeout(timer)
});

var timer = setTimeout(function(){
  console.log("超时了");
  ajax.abort();
},3200)

注意,这里出现了一个新方法:abort——在ajax发送后,回调未执行之前取消ajax的回调的方法。仔细观察代码,这两段代码高度耦合,ajax回调里面清除定时器,定时器里面取消ajax。

用promise的race方法就可以避免这种耦合,看代码:

代码语言:javascript
复制
var p1 = function(url) {
    return new Promise(function(resolve, reject) {
        $.get(url,
        function(data) {
            resolve(data);
        })
    })
}
var p2 = function() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve("超时了,进行默认操作");
        },
        1200)
    })
}
Promise.race([p1("https://cnodejs.org/api/v1/topics?tab=good"), p2()]).then(function(result) {
    console.log(result);
})

通过修改时间来测试一下代码,then方法中接受的数据,根据时间的不同有时可能是data,有时可能是‘超时了...’,并且两段代码不会相互耦合。

race方法的的参数也是一个数组,数组每一项都是promise对象。

和all方法不同的是,all会把所有promise对象resolve的数据传递到then中,race只传递最先返回的那个promise resolve的值。race的中文意思是竞赛:谁最先返回就将谁的值传递下去。

熟练使用promise的all和race会使你的代码易于维护、简洁明了,快打开编辑器测试一下上面的代码吧!

有疑问可给此公众号发送信息。

欢迎转发!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 nodejs全栈开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档