简单概括回调函数promise、generator、async的进化

113 阅读1分钟

回调函数

在ajax出来之后异步开始变多了,我们就有了最常见的同步化需求例如回调函数。

$.ajax({
  url:...,
  type:...,
  success:function(res){
    $.ajax({
      url:...,
      type:...,
      success:function(res){
        $.ajax({
          url:...,
          type:...,
          success:function(res){
  
          }
        })
      }
    })
  }
})

下一次的请求需要依赖上一次请求的返回结果,所以需要层层嵌套,这个就叫做回调地狱。这种回调地狱在逻辑简单时还好,当逻辑复杂时,维护起来就非常麻烦,需要一层一层的剥开。

Promise

在ES6之后有了Promise对回调地狱进行了优化。使其从三角形的嵌套模式变为线性模式,使其更加直观便于维护。Promise有三种状态:pending(进行中)、resolved(成功)、rejected(失败)。

new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve("省")
  },1000)
}).then((res)=>{
  console.log(res)
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve("市")
  	},1000)
  })
}).then((res)=>{
  console.log(res)
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve("区")
  	},1000)
  })
})

其中Promise有两个主要用法:Promise.all和Promise.race。

let wake = (time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time / 1000}秒后醒来`)
    }, time)
  })
}

let p1 = wake(3000)
let p2 = wake(2000)

Promise.all([p1, p2]).then((result) => {
  console.log(result)       // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
  console.log(error)
})

Promise.all相当于“且”,当所有的任务完成之后再以数组的形式统一返回所有的resolve。

let wake = (time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time / 1000}秒后醒来`)
    }, time)
  })
}

let p1 = wake(3000)
let p2 = wake(2000)

Promise.race([p1, p2]).then((result) => {
  console.log(result)       // '2秒后醒来' 
}).catch((error) => {
  console.log(error)
})

Promise.race相当于“或”,哪一个任务先完成,就返回这个resolve。

Generator

尽管Promise解决了回调地狱的问题,但是在Promise的线性模式中,任然存在回调。Generator是一个可以暂停和继续执行的函数,其实在ES6中的Generator不是专门用来解决Promise的回调问题的。但是其状态机模式可以很好的解决异步回调的问题。
Generator 基本语法包含两部分:函数名前要加一个星号;函数内部用 yield 关键字返回值。yield,表达式本身没有返回值,或者说总是返回undefined。next,方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。只有访问了next()才能执行下一步。

function * foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);

}

var b = foo(5); 
console.log(b.next()) // { value: 6, done: false }
console.log(b.next(12)) // { value: 8, done: false }
console.log(b.next(13)) // { value: 42, done: true }

其中done表示是否执行完成,在还未执行完yield之前,done为false,完成之后done为true。

Async/Await

Async其实就是Generator的语法糖,解决了Generator需要手动调用next的问题。其中async 对应的是 * ,await 对应的是 yield 。

async function asyyy(){
  let data1 = await request('GET','http:.....')
  return data2 = await request('POST','http:.....',{id: data1.id})
}

function request(type,url,params){
  return new Promise({
    $.ajax({
      url: url,
      type: type,
      data: params,
      success:function(res){
        resolve(res)
      },
      error:function(err){
        reject(err)
      }
    })
  })
}

返回值是 Promise。async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。 进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。