simplify the life

获取 JavaScript 异步函数返回值的笔记

wrong action

function asyncfunc() {
  let ret = 100;

  setTimeout(() => {
    return ret;
  }, 1000)
}

let ret = asyncfunc()
console.log(ret) // undefined

callback

function asyncfunc(callback) {
  let ret = 100;

  setTimeout(() => {
    callback(ret)
  }, 1000)
}

function callback(ret) {
  // 处理异步获取的数据
  console.log(ret)
}

asyncfunc(callback)

promise

function asyncfunc() {
  let ret = 100

  return new Promise(function(resolve) {
    setTimeout(() => {
      resolve(ret)
    }, 1000)
  })
}

asyncfunc().then(value => {
  // 处理异步获取的数据
  console.log(value)
})

generator

function asyncfunc() {
  let ret = 100

  setTimeout(() => {
    it.next(ret)
  }, 1000)
}

function *gen() {
  let ret = yield asyncfunc()
  
  // 处理异步获取的数据
  console.log(ret)
}

let it = gen()
it.next()

generator + promise

function asyncfunc() {
  let ret = 100

  return new Promise(resolve => {
    setTimeout(() => {
      resolve(ret)
    }, 1000)
  })
}

function *gen() {
  let ret = yield asyncfunc()
  
  // 处理异步获取的数据
  console.log(ret)
}

let it = gen()
it.next().value.then(value => {
  it.next(value)
})

promise 解决了回调地狱的痛点,但是还是有回调;generaror 使得异步可以像同步一样书写,但是无法自动执行,需要多次调用 it.next();async/await 是 generator 的语法糖,使得 iterator 可以自动执行

暂时没发现 generator + promise 的正确使用姿势(只发现了 asyncfunc() 方法內可以不使用 it 变量,使得 asyncfunc() 方法更加干净,但是上面的例子引入了 promise 的回调,有点回到旧时代的感觉),待学习

2017/11/06: generator 和 promise 搭配使用,可能是为了能使错误捕获更加顺利

async/await

async关键字告诉 JavaScript 编译器对于标定的函数要区别对待。当编译器遇到await函数的时候会暂停。它会等到await标定的函数返回的 promise。该 promise 要么得到结果、要么 reject。

function asyncfunc() {
  let ret = 100

  return new Promise(resolve => {
    setTimeout(() => {
      resolve(ret)
    }, 1000)
  })
}

(async function() {
  let ret = await asyncfunc()

  // 处理异步获取的数据
  console.log(ret)
})()

所有的异步代码必须写在 new Promise 的逻辑里

如果你想获取一个 async 函数的结果,你需要使用 Promise 的 then 语法:(async 函数的执行结果会自动变成一个 Promise)

async function doubleAndAdd(a, b) {
  a = await doubleAfter1Sec(a)
  b = await doubleAfter1Sec(b)
  return a + b
}

function doubleAfter1Sec(param) {
  return new Promise(resolve => {
    setTimeout(() => resolve(param * 2), 1000)
  })
}

doubleAndAdd(1, 3).then(console.log) // 8

在上面的例子中,我们显示地调用了 await 两次,因为每次都等待了 1 秒钟,因此总计两秒钟。现在,我们可以使用 Promise.all 函数来让他们并行处理。

async function doubleAndAdd(a, b) {
  [a, b] = await Promise.all([doubleAfter1Sec(a), doubleAfter1Sec(b)])
  return a + b
}

function doubleAfter1Sec(param) {
  return new Promise(resolve => {
    setTimeout(() => resolve(param * 2), 1000)
  })
}

doubleAndAdd(1, 3).then(console.log) // 8

posted on 2017-10-30 21:59 韩子迟 阅读(...) 评论(...) 编辑 收藏

导航

统计信息

News