博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript异步发展史
阅读量:7054 次
发布时间:2019-06-28

本文共 4159 字,大约阅读时间需要 13 分钟。

JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。 正如我们所知道的那样,在JavaScript中,异步编程方式只能通过JavaScript语言中的一等公民函数才能完成:这种方式意味着我们可以将一个函数作为另一个函数的参数,在这个函数的内部可以调用被传递进来的函数(即回调函数)。

let fs = require('fs'); fs.readFile('./1.txt','utf8',function(err,data){ if(err){//如果err有值,就表示程序出错了 console.log(err); }else{//如果error为空,就表示 成功了,没有错误 console.log(data); } })复制代码

回调函数的问题

    1. 无法捕获错误 try catch
    1. 不能return
    1. 回调地狱
function read(filename){ fs.readFile(filename,'utf8',function(err,data){ throw Error('出错了') if(err){//如果err有值,就表示程序出错了 console.log(err); }else{//如果error为空,就表示 成功了,没有错误 console.log(data); } }) } try{ read('./1.txt'); }catch(e){ console.log('err',e); };复制代码

当你访问服务器的时候,比如要请求一个HTML页面,比如是用户列表。服务器一方面会去读取读模板文件,可能是ejs pug jade handlebar ,另外一方面还要读取数据(可能会放在文件里,也可以会放在数据里),它们都很慢,所以都是异步的。

这种恶魔金字塔有以下问题

    1. 非常难看
    1. 非常难以维护
    1. 效率比较低,因为它们是串行的
fs.readFile('./template.txt', 'utf8', function (err, template) {  fs.readFile('./data.txt', 'utf8', function (err, data) {    console.log(template + ' ' + data);  })})复制代码

如何解决这个回调嵌套的问题

1.通过事件发布订阅来实现 这是node核心模块中的一个类,通过它可以创建事件发射器的实例,里面有两个核心方法,一个叫on emit,on表示注册监听,emit表示发射事件

let EventEmitter = require('events');let eve = new EventEmitter();//这个html对象是存放最终数据let html = {};//template data//监听数据获取成功事件,当事件发生之后调用回调函数eve.on('ready',function(key,value){  html[key] = value;  if(Object.keys(html).length == 2){    console.log(html);  }});fs.readFile('./template.txt', 'utf8', function (err, template) {  //1事件名 2参数往后是传递给回调函数的参数  eve.emit('ready','template',template);})fs.readFile('./data.txt', 'utf8', function (err, data) {  eve.emit('ready','data',data);})*///通过一个哨兵函数来处理function done(key,value){  html[key] = value;  if(Object.keys(html).length == 2){    console.log(html);  }}复制代码

ES6的很多特性都跟Generator扯上关系,而且实际用处比较广, 包含了任何需要异步的模块, 比如ajax, filesystem, 或者数组对象遍历等都可以用到; Generator函数和普通的函数区别有两个, 1:function和函数名之间有一个*号, 2:函数体内部使用了yield表达式;比如这样:

/** * 生成器是一个函数,可以用来生成迭代器 * 生成器函数和普通函数不一样,普通函数是一旦调用一定会执行完 * 但是生成器函数中间可以暂停,可以执行一会歇一会 *///生成器函数有一个特点,需要加个*//生成器有若干个阶段,如何划分这些阶段呢?function *go(a){    console.log(1);    //此处的b用来供外界输入进来的    //这一行实现输入和输出,本次的输出放在yield后面,下次的输入放在yield前面    let b =  yield a;    console.log(2);    let c = yield b;    console.log(3);    return c;}//生成器函数和普通的函数不一样,调用它的话函数并不会立刻执行//它会返回此生成器的迭代器,迭代器是一个对象,每调用一次next就可以返回一个值对象let it = go("a值");//next第一次执行不需要参数,传参数没有意义let r1 = it.next();//第一次调用next会返回一个对象,此对象有两个属性,一个是value就是yield后面那个值,一个是done表示是否迭代完成console.log(r1);//{ value: 'a', done: false }let r2 = it.next('B值');console.log(r2);//{ value: 'B值', done: false }let r3 = it.next('C值');console.log(r3);//{ value: 'C值', done: true }复制代码

!重点来了

先回忆之前promise对异步的实现,以 bluebird为例:

let Promise = require('bluebird');let fs = require('fs');function promisifyAll(obj) {  for (let key in obj) {    if (obj.hasOwnProperty(key) && typeof obj[key] == 'function') {      obj[key+'Async'] = Promise.promisify(obj[key]);    }  }}//它会遍历对象上面的所有方法,然后对每个方法添加一个新的方法 AsyncpromisifyAll(fs);fs.readFileAsync('./1.txt', 'utf8').then(data => console.log(data));复制代码

现在将Generator与promise综合在一起:

let fs = require('fs');function readFile(filename) { return new Promise(function (resolve, reject) {   fs.readFile(filename, 'utf8', function (err, data) {     err ? reject(err) : resolve(data);   }); })}function *read() { console.log('开始'); let a = yield readFile('1.txt'); console.log(a); let b = yield readFile('2.txt'); console.log(b); let c = yield readFile('3.txt'); console.log(c); return c;}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,reject);       }   }() });}co(read).then(function (data) { console.log(data);});复制代码

随着 Node 7的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await

let Promise = require('bluebird');let readFile = Promise.promisify(require('fs').readFile);async function read() {  //await后面必须跟一个promise,  let a = await readFile('./1.txt','utf8');  console.log(a);  let b = await readFile('./2.txt','utf8');  console.log(b);  let c = await readFile('./3.txt','utf8');  console.log(c);  return 'ok';}read().then(data => {  console.log(data);});复制代码

async await是语法糖,内部还是用generator+promise实现

转载地址:http://allol.baihongyu.com/

你可能感兴趣的文章
Python_反射
查看>>
Codeforces-963 D Frequency of String
查看>>
MyBatis-mybatis全局映射文件解析
查看>>
WebApi 跨域解决方案 --CORS
查看>>
MySQL系列详解五: xtrabackup实现完全备份及增量备份详解-技术流ken
查看>>
单独编译Android源代码中的模块
查看>>
manjaro安装mysql5.7
查看>>
记录零散的知识点
查看>>
H5上传图片并使用canvas制作海报
查看>>
springmvc学习笔记
查看>>
LRU算法的设计
查看>>
Java util包中常用的类和方法
查看>>
[R] 之 管理工作空间函数
查看>>
将windows目录共享到linux
查看>>
计算机是如何启动的
查看>>
Python的raw_input语句包含中文,在Windows环境CMD中显示乱码的解决方法
查看>>
HIbernate学习笔记3 之 缓存和 对象的三种状态
查看>>
2015.3.12Arinc424 Tools中SiniArincCls.csParserFile(string sFile)函数正则表达式理解
查看>>
angularjs探秘<三> 控制器controller及angular项目结构
查看>>
列表的常用操作符和BIF
查看>>