当前位置: 首页 > 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
  • 「译」Node.js Streams 基础
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • ECS应用管理最佳实践
  • GitUp, 你不可错过的秀外慧中的git工具
  • Gradle 5.0 正式版发布
  • laravel5.5 视图共享数据
  • SQLServer插入数据
  • 老板让我十分钟上手nx-admin
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 提醒我喝水chrome插件开发指南
  • 微服务框架lagom
  • 硬币翻转问题,区间操作
  • 7行Python代码的人脸识别
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 函数计算新功能-----支持C#函数
  • #Lua:Lua调用C++生成的DLL库
  • $ git push -u origin master 推送到远程库出错
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (C#)一个最简单的链表类
  • (Ruby)Ubuntu12.04安装Rails环境
  • (ZT)薛涌:谈贫说富
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (五)Python 垃圾回收机制
  • (循环依赖问题)学习spring的第九天
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • **PHP分步表单提交思路(分页表单提交)
  • .axf 转化 .bin文件 的方法
  • .htaccess配置重写url引擎
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net core 控制台应用程序读取配置文件app.config
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .net和php怎么连接,php和apache之间如何连接
  • .net生成的类,跨工程调用显示注释
  • .sh