用四种方法将两个AJAX改为同步

Promise、Generator函数、yield、async/await 相关


今有一题,题目为:

  1. 现有ajax1()ajax2(),用于快速初始化CODE1和CODE2
  2. myFunc必须在CODE1和CODE2初始化之后再执行
  3. 可以在原代码上修改

伪代码为:

Ajax1({
    ...
    success: function(data){
        CODE1 = data
    }
})

Ajax2({
    ...
    success: function(data){
        CODE2 = data
    }
})

myFunc(CODE1, CODE2)

立Flag判断

作为一个后端,我最先想到的是创建一个变量来标志两个ajax是否完成,然后再两个ajax的回调中进行判断(至于两个ajax都改为同步这种方法直接不考虑),大致代码如下:

使用了setTimeOut来模拟ajax:

let CODE1 = null
let CODE2 = null
function myFunc() {
  console.log(CODE1, CODE2);
}

//第一种
let flag = 0 //flag默认为0

function ajax1() {
  setTimeout(() => {
    console.log('ajax1得到响应')
    CODE1 = 'ajax1返回的数据'
    //如果回调时flag为1,代表另一个ajax已经初始化成功
    if (flag === 1) {
      myFunc()
    } else {
      //否则flag+1代表本ajax成功
      flag += 1
    }
  }, 1000)
}

function ajax2() {
  setTimeout(() => {
    console.log('ajax2得到响应')
    CODE2 = 'ajax2返回的数据'

    if (flag === 1) {
      myFunc()
    } else {
      flag += 1
    }
  }, 2000)
}

ajax1()
ajax2()

执行结果:

第一种

可以看到myFunc在两个ajax执行完成之后才执行。

yield关键字

yield关键字是ES6添加的语法,可以在函数执行中交出运行权限

上面第一种方法一看就是不会前端的人写的,前端如果要想炫技的话可以这么写:

//第二种

//Promise执行器
function run(gen) {
  gen = gen()
  return next(gen.next())

  function next({ done, value }) {
    return new Promise(resolve => {
      if (done) {
        resolve(value)
      } else {
        value.then(data => {
          next(gen.next(data)).then(resolve)
        })
      }
    })
  }
}

function ajax1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('ajax1得到响应');
      CODE1 = 'ajax1返回的数据'
      resolve()
    }, 5000)
  })
}

function ajax2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('ajax2得到响应');
      CODE2 = 'ajax2返回的数据'
      resolve()
    }, 5000)
  })
}

function* call() {
  let aj1 = ajax1()
  let aj2 = ajax2()
  yield aj1
  yield aj2
}

run(call).then(myFunc)

什么意思我解释不清楚,也不想解释,自己去看阮一峰的博客:Generator 函数的含义与用法

async/await关键字

async/await关键字是ES7的语法,是对上面Promise执行器的一种简化:

// 第三种

function ajax1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('ajax1得到响应');
      CODE1 = 'ajax1返回的数据'
      resolve()
    }, 1000)
  })
}

function ajax2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('ajax2得到响应');
      CODE2 = 'ajax2返回的数据'
      resolve()
    }, 2000)
  })
}

async function call() {
    /* 
    这里不能这么写:
    await ajax1()
    await ajax2()
    这样会在ajax1之后才会执行ajax2
    需要写成下面的这种:
    */
  let aj1 = ajax1()
  let aj2 = ajax2()
  await aj1
  await aj2
  myFunc()
}

call()

async声明这是一个内部存在同步的函数,只有声明了async,函数内部才能使用await,await代表等待Promise执行完毕才会继续执行,的确有点同步的感觉了。

Promise

上面用到了Promise但是都没介绍,就是想把最合适的一种放到最后:

//第四中,同时也是最优解

function ajax1(resolve, reject) {
    setTimeout(()=>{
        console.log('ajax1得到响应');   
        CODE1 = 'ajax1返回的数据'
        resolve()
    },1000)
}

function ajax2(resolve, reject) {
    setTimeout(()=>{
        console.log('ajax2得到响应');   
        CODE2 = 'ajax2返回的数据'
        resolve()
    },2000)
}

const p1 = new Promise(ajax1)
const p2 = new Promise(ajax2)

Promise.all([p1, p2]).then(myFunc)

函数Promise.all()接收一个Promise数组参数,作用是数组内的Promise执行完毕之后会返回一个Promise对象。(还有一个Promise.race()方法也挺好玩,作用是参数中任意一个Promise完成就返回一个Promise)

标签: JavaScript

添加新评论