4

《javascript高级程序设计》学习笔记 | 11.1.异步编程

 2 years ago
source link: https://segmentfault.com/a/1190000040614575
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关注前端小讴,阅读更多原创技术文章

  • ES6 新增了正式的Promise引用类型,支持更优雅地定义和组织异步逻辑
  • 接下来的几个版本,使用asyncawait关键字定义异步函数的机制

相关代码 →

同步与异步

  • 同步行为在内存中顺序执行处理器指令

    • 每条指令都在单个线程按出现顺序执行
    • 每条指令执行后,都可以推断出程序的状态,并立即获得存储在系统本地(或寄存器或系统内存)的信息
let x = 3 // 操作系统在栈内存上分配一个存储浮点数值的空间
x = x + 4 // 针对这个值做一次数学计算,并把计算结果写回之前分配的内存中
  • 异步行为类似于系统中断

    • 当前进程外部的实体可以触发代码执行,通常在定时回调中执行
    • 执行线程不知道何时将信息存储到系统本地(或寄存器或系统内存),取决于回调合适从消息队列出列并执行
let x2 = 3 // 操作系统在栈内存上分配一个存储浮点数值的空间
setTimeout(() => {
  x = x + 4 // 执行线程不知道x值何时会改变,取决于回调何时从消息队列出列并执行
}, 1000)

以往的异步编程方式

  • 早期的 JS 只支持回调函数表明异步操作,串联多个异步操作需深度嵌套回调函数(回调地狱
function double(value) {
  setTimeout(() => {
    setTimeout(() => {
      console.log(value * 2)
    }, 2000) // 2000毫秒后,JS运行时会把回调函数推到消息队列上等待执行
  }, 1000) // 1000毫秒后,JS运行时会把回调函数推到消息队列上等待执行
}
double(3) // 6(约3000毫秒后),double()函数在setTimeout成功调度异步操作后,立即退出

异步返回值

  • setTimeout操作返回有用的值,可给异步操作提供一个回调,把这个值传给需要它的地方
function double2(value, callback) {
  setTimeout(() => {
    callback(value * 2) // 1000毫秒后,把回调函数推到消息队列上
  }, 1000)
}
double2(3, (x) => console.log(`I was given: ${x}`)) // 'I was given: 6'(约1000毫秒后)
  • 在回调模型中做异步操作的失败处理(成功回调 & 失败回调)
  • 该方法已不可取,因为必须在初始化异步操作时定义回调,异步函数返回值只在短时间内存在,必须预备好将该返回值作为参数的回调才能接收到它
function double3(value, success, failure) {
  setTimeout(() => {
    // 必须在初始化异步操作时定义回调
    try {
      if (typeof value !== 'number') {
        throw 'Must provide number as first argument'
      }
      success(value * 2)
    } catch (error) {
      failure(error)
    }
  }, 1000)
}
const successCallback = (x) => console.log(`Success: ${x}`)
const failureCallback = (e) => console.log(`Failure: ${e}`)
double3(3, successCallback, failureCallback) // 'Success: 6'(约1000毫秒后)
double3('3', successCallback, failureCallback) // 'Failure: Must provide number as first argument'(约1000毫秒后)

嵌套异步回调

  • 异步返回值依赖另一个异步返回值,则需要嵌套回调回调地狱,不具有扩展性,代码难以维护)
function double4(value, success, failure) {
  setTimeout(() => {
    try {
      if (typeof value !== 'number') {
        throw 'Must provide number as first argument'
      }
      success(value * 2)
    } catch (error) {
      failure(error)
    }
  }, 1000)
}
const successCallback2 = (x) => {
  double4(x, (y) => console.log(`Success: ${y}`)) // 异步返回值依赖另一个异步返回值,嵌套回调产生“回调地狱”
}
const failureCallback2 = (e) => console.log(`Failure: ${e}`)
double4(3, successCallback2, failureCallback2) // 'Success: 12'(约2000毫秒后)

总结 & 问点

  • 在执行线程和内存存储方面,同步行为和异步行为有哪些区别?
  • 写一段代码,将 setTimeout 的返回值作为回调传给函数,并执行这个函数获取结果
  • 写一段代码,在回调模型中做异步操作的成功/失败处理,并说说为什么该方法已经不可取
  • 回调地狱是如何形成的?其有什么缺点?

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK