为了账号安全,请及时绑定邮箱和手机立即绑定

多次请求因为网络无法保证响应顺序,如何保证获得所有响应结果后生成的列表结果的顺序与请求顺序一致?

多次请求因为网络无法保证响应顺序,如何保证获得所有响应结果后生成的列表结果的顺序与请求顺序一致?

有只小跳蛙 2019-02-25 13:12:56
看很多人都误会成了一次性发送10次,补充为这样:假如用户可以连续点击按钮,每次发1次请求,每次获得响应结果后会生成一个li,因为网络状态的影响后发出的请求可能先响应,假如点了10次,如何保证10个li的顺序与请求的顺序一致!使用Promise.all的答案肯定都是不对的,因为你无法预测用户点击按钮的时机,用户可能一两秒完成10次点击,但也可能在10秒内完成......肯定不能说我等用户点完10次再使用Promise.all请求,何况实际情况不一定是10次。这是我一次面试唯一没答的很好的题目,所以印象比较深刻,我开始也答的Promise.all,被直接否定,后面我提到在请求报文中携带相关参数,响应中返回,本地做mapping关系来实现,但面试官依然不是很满意。后面经我询问后面试官只提到了思路,说了几个词记得不是很清楚,后续查资料猜测貌似是在请求响应包含一个Request-Id字段,并使用 UUID 作为该值......没实践过不敢确定!
查看完整描述

10 回答

?
眼眸繁星

TA贡献1873条经验 获得超9个赞

Promise.all可以保证顺序但是得等到所有请求完毕才会触发


function p1(time) {

    return new Promise(function (resolve, reject) {

        setTimeout(function () {

            resolve(time);

        }, time);

    })

}


Promise.all([p1(5000), p1(1000)]).then(function (res) {

    console.log(res);//[5000,1000]

});


查看完整回答
反对 回复 2019-03-26
?
郎朗坤

TA贡献1921条经验 获得超9个赞

在请求的时候带过去要显示的li的顺序;然后响应回来顺序;按顺序排列吧


查看完整回答
反对 回复 2019-03-26
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

一,可以把请求回来的数据做一个标识,然后把所有数据 都放到一个数组中,按标识 排序。
二,使用Promise.all,接收的是一个数组,等到数组中的请求全部完成,就执行Promise.all().then(values => {}),其中values就是一个数组,且排好序的

查看完整回答
反对 回复 2019-03-26
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

万无一失的方法是:
从第一个开始执行,等第一个执行结束后,再执行第二个,依次类推。
这种同步方法效率太低。
那么可以考虑Promise.all呢?
担心promise.all中的所有task都是异步执行的?
那么真正返回结果是依task列表顺序返回,所以就它了。

查看完整回答
反对 回复 2019-03-26
?
jeck猫

TA贡献1909条经验 获得超7个赞

以下代码实现了:

  • 并发请求

  • 顺序操作

  • 不需要等待全部请求完毕

  • 可以直接运行

(()=>{

    Promise.allInOrder = (promises, thenForEach)=>{

        let sequence = Promise.resolve();

        

        promises.forEach(function(request){

            sequence = sequence.then(function(){

              return request.then(thenForEach);

          });

        });


    };

})();


// test

(()=>{

    let timeConsumingFunc = param=>new Promise(

            (resolve)=>{

                let timeout = Math.random() * 5000;

                console.log(`task ${param} will be resolved in ${timeout}ms`);

                setTimeout(()=>{

                    console.log(`${param} resolved`);

                    resolve(param+10);

                }, timeout);

            }

        );

    Promise

        .allInOrder(

            [timeConsumingFunc(1), timeConsumingFunc(2), timeConsumingFunc(3)],

            d=>{

                return new Promise(function(resolve) {

                  console.log(d);

                resolve();

              });

            }

        )

})();

这是我以前的一个提问的最终解决方法,也可以采用我采纳的哪个答案,只是代码会臃肿一些

补充:
针对你说的情况,可以间隔1s内的鼠标点击作为一组请求用上面方法并发请求,间隔大于1s的同步继发操作


查看完整回答
反对 回复 2019-03-26
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

在请求里带一个时间戳参数,然后再原封不动把这个时间戳返回来,并根据时间进行排序。


查看完整回答
反对 回复 2019-03-26
?
慕少森

TA贡献2019条经验 获得超9个赞

其实如果后天和前台能够联动,最好是请求时有一个标号,然后返回时带标号,这样肯定没有问题,且无论多少返回都可以先展示,后期再依序调整。
其实如果更友好的,发一次请求,就在数组中填一个展位符信息,接收到一个就更新数组,并刷新展示。

查看完整回答
反对 回复 2019-03-26
?
当年话下

TA贡献1890条经验 获得超9个赞

我的话可能会这么做:


function Ajax (option) {

    this.list = []

    let ajax = (data) => {

        let i = arr.length

        this.list[i] = '等待结果'

        $.ajax(option.url, {

            data:data

            // ...

            success: (res) => {

                this.list[i] = res

                option.success(res, i)

            }

        })

    }

    return ajax

}

let userAjax = new Ajax({url:xxx,method:xxx})

每次请求,直接userAjax(data),然后请求结果的顺序在list上固定好的,怎么响应影响不了

然后看你说响应里加字段,那就是后端控制了,你只需要对id进行排序,不过感觉跟你前面说的携带相关参数,响应中返回,本地做mapping关系来实现没什么区别啊,只不过一个前端生成uuid,一个后端生成uuid。


查看完整回答
反对 回复 2019-03-26
  • 10 回答
  • 0 关注
  • 1051 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信