当前位置: 首页 > news >正文

JavaScript异步流程控制的前世今生

JavaScript异步流程控制的前世今生

JavaScript

javascript在设计之初.为了避免资源管理复杂问题(多个线程同时操作dom,以哪个为准),因此被设计成为了单线程语言.

说起异步就不得不提回调, 为了解决多重回调嵌套导致代码难以维护问题.javascript一直都在完善这个解决方案.

在10多年中javascript 异步流程控制经过了

callback -> event -> promise -> yield & co -> async await

Callback

ES6之前异步编程最常用的方法,如果回调函数嵌套层数较深,代码将变得难以维护.并且在回调函数之外无法捕获回调函数中的异常.

var fs = require('fs')

try {
  fs.readFile('file', 'utf8', function(err, data){
    // if (err) {
    //   console.log(err)
    // } else {
      console.log(data)
    // }
  })
} catch(e) {
  console.log(e)
}  

尝试读取一个不存在的文件时.外层的try/catch 无法捕获这一异常.将输出 undefine.
callback异步操作,异步调用的本体和callback属于不同的事件循环.而try/catch 只能捕获当前事件的异常.因此将无法捕获

Event (发布/订阅模式)

采用事件驱动模式.任务的执行不取决于代码的顺序,由某个事件来决定

var EventEmitter = require('events') 
var fs = require('fs')

var eve = new EventEmitter()

// 监听read事件
eve.on('read', function(value){
  console.log(value)
})
// 执行一个异步读取
fs.readFile('./template.txt', 'utf8', function (err, data) {
  if (err) {
    console.log(err)
  } else {
    // 拿到数据后 发送一个read事件.并传递数据 
    eve.emit('read', data)
  }
})

Promise

在ES6中提供了promise对象.给外界提供了统一的API.可用同步操作的流程来表达异步操作.避免了callback 中的嵌套层数过深,不便维护的弊端.

var fs = require('fs')

function read (path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function(err, data){
      if (err) {
        reject(err)
      } else {
        console.log(data)
        resolve()
      }
    })
  })
}

read('./1.txt').then(function(){
  return read('./2.txt')
}).then(function(){
  return read('./3.txt')
}).then(function(){
  console.log('执行结束')
})

yield && co

通过Generator函数封装异步任务.在需要暂停的地方使用yield

var fs = require('fs')

function *getData () {
 var a = yield readFile('./1.txt')
 console.log(a)
 var b =  yield readFile('./2.txt')
 console.log(b)
 var c =  yield readFile('./3.txt')
 console.log(c)
}

function readFile(path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

function co(gen) {
  var fn = gen()
  var lastVal
  return new Promise(function(resolve, reject){
    !function next(lastVal) {
      var {value, done}  = fn.next(lastVal)
      if (done) {
        resolve()
      } else {
        value.then(next, reject)
      }
    }()
  })
}

co(getData)

async/await

Async/Await应该是目前最简单的异步方案了

  • async 表示这是一个async函数,await只能用在这个函数里面
  • await 表示在这里等待promise返回结果了,再继续执行。
  • await 后面跟着的应该是一个promise对象(其他返回值也可以,只是会立即执行)
  • 捕获错误
var fs = require('fs')

async function getData () {
  try {
    var a = await readFile('file')
  } catch(e) {
    console.log(e)
  }  
  var b =  await readFile('./2.txt')
  console.log(b)
  var c =  await readFile('./3.txt')
  console.log(c)
}

function readFile(path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

getData()

参考文章
Generator 函数的含义与用法

相关文章:

  • 全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装爬虫框架Scrapy(离线方式和在线方式)(图文详解)...
  • 泛型的应用
  • 生成字符Banner
  • 通过例子理解 k8s 架构 - 每天5分钟玩转 Docker 容器技术(122)
  • tomcat 和 数据库的连接
  • 使用laravel构建spa
  • MyBatis 缓存机制深度解剖 / 自定义二级缓存
  • weex打包android apk采坑之旅(windows)
  • 7-设计模式-代理模式
  • 如何统计序列中元素的出现频度
  • DirectX3D设备丢失(lost device)的处理(一)
  • Ubuntu12.04_X64 apt-get install 报错404
  • 面试必问的volatile,你了解多少?
  • Day04——Python模块
  • [UWP]附加属性2:实现一个Canvas
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Android Studio:GIT提交项目到远程仓库
  • Angular Elements 及其运作原理
  • HTML-表单
  • Laravel核心解读--Facades
  • LintCode 31. partitionArray 数组划分
  • Redis 中的布隆过滤器
  • sessionStorage和localStorage
  • spring boot下thymeleaf全局静态变量配置
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 阿里研究院入选中国企业智库系统影响力榜
  • 前端之Sass/Scss实战笔记
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 数据结构java版之冒泡排序及优化
  • 网页视频流m3u8/ts视频下载
  • 我的zsh配置, 2019最新方案
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (三十五)大数据实战——Superset可视化平台搭建
  • (转)人的集合论——移山之道
  • ******之网络***——物理***
  • .gitattributes 文件
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .NET NPOI导出Excel详解
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .NET轻量级ORM组件Dapper葵花宝典
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @Pointcut 使用
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • [AHOI2009]中国象棋 DP,递推,组合数
  • [C/C++] -- 二叉树
  • [C/C++]数据结构 堆的详解
  • [halcon案例2] 足球场的提取和射影变换
  • [LLM]大模型八股知识点(一)
  • [NISACTF 2022]easyssrf
  • [POJ1236]Network of Schools(并查集+floyd,伪强连通分量)
  • [Real world Haskell] 中文翻译:第三章 定义类型,流式函数
  • [UE4]Animation Montage C++相关注意事项
  • [Windows] Win11 常用快捷键
  • [个人]加入了ruby hacking guide的中文翻译团队