记录一个关于ajax顺序的面试题

最近面试的时候遇到了一个关于ajax处理顺序的问题,当时没有想到自己感觉满意的思路,回家后想了一个自己还算满意的思路,记录一下。

题目

页面有两个按钮 A和B,以及一个输入框,A按钮点击后发送一个请求,返回一个字符串A,B也发请求,但返回字符串B,返回后会把字符串赋值给输入框,但是A,B发送的两个请求返回的时间不同,点击两个按钮的顺序也不一定,B要比A先返回,而最终效果要求是输入框字符的顺序是AB。 然后题目给了点样板代码,我记得不是很清楚了,大致是这些:

function ajaxA()  // 返回promise
function ajaxB() // 返回promise
function setText(text)
btnA.onclick=function(){
    
}
btnB.onclick=function(){
    
}
复制代码

当时大致是这些吧,然后面试官说ajaxA,ajaxB,一个setText不需要我们实现也就是我们不用考虑他们,所以我们自己实现的重点是两个点击事件里面怎么写,可以加点代码。

当时的思路

我当时脑海中就想到了Promise.all因为我看到两个请求返回了promise,而且根据题目要求的话我得等两个请求都返回了再设置输入框,同时在all里面按顺序放入A promise和B promise,可当时就被面试官否定了,他说ajax返回的时间顺序不定...反正意思是你在all最后拿到的顺序是错的跟你传入的数组的顺序可能不一致,我当时脑子还真没印象这个顺序到底是不是跟我在all里面传入的数组循序一致,因为我还真没用过这个all,当时心一下虚了,毕竟是面试官嘛。 当时我还有另个思路就是同步请求,当然这是最简单了,按顺序写代码就可以了。

后来的思路

回家后我试了试Promise.all,发现最后返回的数组顺序是根据我传入的数组的顺序,nnd,面试官怎么说不一致呢?

var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'foo');
}); 
var p2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'p2');
}); 

Promise.all([ p2, p3]).then(values => { 
  console.log(values); // [ 'p2', "foo"]
});
复制代码

测试看到虽然 p3比p2先resolve,但是由于我传入的顺序是p2,p3所以最后values依然是按照p2 ,p3 的顺序把结果放入了values。wtf,面试官坑我?

另一个思路:回家后我一直在想不用Promise.all怎么搞定。 顺着一个线索我要用promise, 我怎么在A 返回的时候等A先赋值,B再赋值,B怎么等待A呢?

然后给室友说了下,他立马说我等A请求成功后再发送B请求,恩,我觉得思路不好,回调地狱啊,另外按照题目要求貌似是点了按钮就立马发请求,两个按钮点击后发请求是没有影响的,不能让A阻塞B请求的发送,但是我们可以让A阻塞B设置输入框值的步骤。

当时脑子里一致在想利用promise 等A返回后我调用一下resolve,B就开始设置输入框的值,但是最终点击事件里面可能是这样子的

btnA.onclick = function () {
            ajaxA().then(res=>{
                setText(res)
            })
        }
btnB.onclick = function () {
            ajaxB().then(res=>{
                setText(res) //要等A设置完再设置B
            })
        }
复制代码

一般我们利用promise是这个姿势

let p=new Promise((resolve,reject)=>{
    ajaxA().then(res=>{
        resolve(res)// 触发p then里面的回调执行
    })
})
p.then(()=>{
    //等待调用resolve 后执行
})
复制代码

这里我不能在点击事件里声明promise p,因为 有可能先点击B,如果此时没点击A的话,p是undefiend,然后脑子开始短路了,思考一会,忽然想起了 vue 中的nextTick,想到了源码在处理nextTick的回调时的代码,我也不知道怎么会想到nextTick的,灵光一现吧,然后赶紧翻了下源码:

看到源码里 new 一个Promise并暂时保存了resolve,这样这个resolve就可以在外面任意调用了,我当时思路就卡在我在A的点击事件里面 怎么去调用一个resolve去控制B的then,万万没想到可以保存resolve啊,这样子的话实现思路就很简洁了。

 function setText(text){
            ipt.value = ipt.value+text
    }
        let _resolve
        const promise=new Promise((resolve,reject)=>{
                _resolve=resolve
            }) 
        btnA.onclick = function () {
            ajaxA().then(res=>{
                setText(res.data)
                _resolve()
            })
        }
        btnB.onclick = function () {
            ajaxB().then(res=>{
                promise.then(()=>{
                    setText(res.data)
               })
            })
        }
复制代码

这就是我满意的思路啦,只增加了一个Promise 和一个_resolve变量。当然会有其他很多思路,我室友也写了下,但是他写的恰恰是我最不想写的思路,加了好几个变量,又是数组保存,又是条件判断的。

 function setText(text){
            ipt.value = text
        }
        let doSth = state =>{
            if (!(state.a && state.b)) return;
            setText(state.prop.join(' '))
        }
        let state = {prop:[],a:false,b:false}
        btnA.onclick = function () {
            ajaxA().then(res=>{
                state.a = true
                state.prop[0] = res.data
                doSth(state)
            })
           
        }
        btnB.onclick = function () {
            ajaxB().then(res=>{
                state.b = true
                state.prop[1] = res.data
                doSth(state)
            })
        }
复制代码

我室友的大致思路,还强行改了一波setText函数,他最后还手动规定了数据放的顺序,他说他的可扩展强...我没看出来,并且代码不简洁。

最后

不用Promise.all你们还有其他优雅思路吗?我第一次处理这类问题,想了解下有没有其他思路,请大佬们说下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值