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

异步

异步

所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段,比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。

这种不连续的执行,就叫做异步。相应地,连续的执行,就叫做同步。

高阶函数

函数作为一等公民,可以作为参数和返回值

可以用于批量生成函数

let toString = Object.prototype.toString;
let isString = function (obj) {
  return toString.call(obj) == `[object String]`;
}
let isFunction = function (obj) {
  return toString.call(obj) == `[object Function]`;
}
let isType = function (type) {
  return function (obj) {
    return toString.call(obj) == `[object ${type}]`;
  }
}

可以用于需要调用多次才执行的函数

let after = function(times,task){
  return function(){
    if(times--==1){
      return task.apply(this,arguments);
    }
  }
}
let fn = after(3,function(){
  console.log(3);});
fn();

异步编程的语法目标,就是怎样让它更像同步编程,有以下几种

  • 回调函数实现
  • 事件监听
  • 发布订阅
  • Promise/A+ 和生成器函数
  • async/await

回调

所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数
fs.readFile('某个文件', function (err, data) {
  if (err) throw err;
  console.log(data);
});

这是一个错误优先的回调函数(error-first callbacks),这也是Node.js本身的特点之一。

回调的问题

异常处理

try{
  //xxx
}catch(e){//TODO}
异步代码时try catch不再生效

let async = function(callback){
  try{
    setTimeout(function(){
      callback();
    },1000)
  }catch(e){
    console.log('捕获错误',e);
  }
}

async(function(){
  console.log(t);
});

因为这个回调函数被存放了起来,直到下一个事件环的时候才会取出,try只能捕获当前循环内的异常,对callback异步无能为力。

Node在处理异常有一个约定,将异常作为回调的第一个实参传回,如果为空表示没有出错。

async(function(err,callback){
  if(err){
    console.log(err);
  }
});
异步方法也要遵循两个原则
  • 必须在异步之后调用传入的回调函数
  • 如果出错了要向回调函数传入异常供调用者判断
let async = function(callback){
try{
  setTimeout(function(){
    if(success)
      callback(null);
    else
      callback('错误');
  },1000)
}catch(e){
  console.log('捕获错误',e);
}
}

回调地狱

异步多级依赖的情况下嵌套非常深,代码难以阅读的维护
let fs = require('fs');
fs.readFile('template.txt','utf8',function(err,template){
fs.readFile('data.txt','utf8',function(err,data){
  console.log(template+' '+data);
})
})

异步流程解决方案

事件发布/订阅模型

订阅事件实现了一个事件与多个回调函数的关联
let fs = require('fs');
let EventEmitter = require('events');
let eve = new EventEmitter();
let html = {};
eve.on('ready',function(key,value){
  html[key] = value;
  if(Object.keys(html).length==2){
    console.log(html);
  }
});
function render(){
  fs.readFile('template.txt','utf8',function(err,template){
    eve.emit('ready','template',template);
  })
  fs.readFile('data.txt','utf8',function(err,data){
    eve.emit('ready','data',data);
  })
}
render();

哨兵变量

let fs = require('fs');

let after = function(times,callback){
  let result = {};
  return function(key,value){
    result[key] = value;
    if(Object.keys(result).length==times){
      callback(result);
    }
  }
}
let done = after(2,function(result){
  console.log(result);
});

function render(){
  fs.readFile('template.txt','utf8',function(err,template){
    done('template',template);
  })
  fs.readFile('data.txt','utf8',function(err,data){
    done('data',data);
  })
}
rende

Promise/Deferred模式

生成器Generators/ yield

当你在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。

上面描述的场景正是JavaScript生成器函数所致力于解决的问题。当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器会遍历每个中断点。
next方法返回值的value属性,是Generator函数向外输出数据next方法还可以接受参数,这是向 Generator 函数体内输入数据

生成器的使用

function* foo () {
  var index = 0;
  while (index < 2) {
    yield index++; //暂停函数执行,并执行yield后的操作
  }
}
var bar =  foo(); // 返回的其实是一个迭代器

console.log(bar.next());    // { value: 0, done: false }
console.log(bar.next());    // { value: 1, done: false }
console.log(bar.next());    // { value: undefined, done: true }
Co

co是一个为Node.js和浏览器打造的基于生成器的流程控制工具,借助于Promise,你可以使用更加优雅的方式编写非阻塞代码。

let fs = require('fs');
function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, function (err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    })
  })
}
function *read() {
  let template = yield readFile('./template.txt');
  let data = yield readFile('./data.txt');
  return template + '+' + data;
}
co(read).then(function (data) {
  console.log(data);
}, function (err) {
  console.log(err);
});
function co(gen) {
  let it = gen();
  return new Promise(function (resolve, reject) {
    !function next(lastVal) {
      let {value, done} = it.next(lastVal);
      if (done) {
        resolve(value);
      } else {
        value.then(next, reason => reject(reason));
      }
    }();
  });
}

Async/ await

使用async关键字,你可以轻松地达成之前使用生成器和co函数所做到的工作

Async的优点

  • 内置执行器
  • 更好的语义
  • 更广的适用性
let fs = require('fs');
function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, 'utf8', function (err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    })
  })
}

async function read() {
  let template = await readFile('./template.txt');
  let data = await readFile('./data.txt');
  return template + '+' + data;
}
let result = read();
result.then(data=>console.log(data));
async 函数的实现

async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function read() {
  let template = await readFile('./template.txt');
  let data = await readFile('./data.txt');
  return template + '+' + data;
}
// 等同于
function read(){
  return co(function*() {
    let template = yield readFile('./template.txt');
    let data = yield readFile('./data.txt');
    return template + '+' + data;
  });
}
async_function- generator

相关文章:

  • 这一次,彻底弄懂TCP三次握手,四次挥手
  • 线程的等待和唤醒
  • js中forEach回调同异步问题
  • 整行读字符串且需分割计算字符串个数
  • 比特大陆新一轮裁员50%,回应称系人员调整
  • zabbix linux系统模板更新
  • 2019.2.20 c++ 知识梳理
  • 微信全局登录设计与实现
  • 朝鲜APT集团Lazarus通过KEYMARBLE Backdoor瞄准俄罗斯组织
  • Less 日常用法
  • 手机端车牌号码键盘的vue组件
  • 回归生活:清理微信公众号
  • Cisco Nexus 系列交换机NX-OS升级
  • React开发实战
  • 工作中总结前端开发流程--vue项目
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【Amaple教程】5. 插件
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • create-react-app做的留言板
  • ES6系列(二)变量的解构赋值
  • golang中接口赋值与方法集
  • js面向对象
  • Laravel 中的一个后期静态绑定
  • Objective-C 中关联引用的概念
  • Protobuf3语言指南
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 二维平面内的碰撞检测【一】
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 如何解决微信端直接跳WAP端
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 源码安装memcached和php memcache扩展
  • 从如何停掉 Promise 链说起
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #14vue3生成表单并跳转到外部地址的方式
  • #define 用法
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (未解决)macOS matplotlib 中文是方框
  • (转)ABI是什么
  • (转)nsfocus-绿盟科技笔试题目
  • 、写入Shellcode到注册表上线
  • .FileZilla的使用和主动模式被动模式介绍
  • .gitignore文件_Git:.gitignore
  • .md即markdown文件的基本常用编写语法
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .net 调用php,php 调用.net com组件 --
  • .NET 指南:抽象化实现的基类
  • .NET中GET与SET的用法
  • @Autowired 与@Resource的区别
  • @JsonSerialize注解的使用
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [8-23]知识梳理:文件系统、Bash基础特性、目录管理、文件管理、文本查看编辑处理...