ES6的异步操作
刚开始看书上的这一章的时候,没想到JavaScript还有异步操作,还有这种操作???果不其然,异步操作和java里面的异步操作同样,还是有点难。不过看了两三遍下来,似乎还是明白了一些。
废话不多说,那就直接进入正题吧!
重要性:JavaScript只有一个 线程,如果没有异步编程,得卡死,基本没法用。
异步
1.概念:简单来说就是不连续的执行,比如说,有一个任务分成两段,先执行第一段,转而执行其他任务,等做好准备再回过头执行第二段。
2.JavaScript语言对异步编程得实现就是回调函数,所谓回调函数,就是把任务的下一阶段单独写在一个函数中,等到重新执行该任务的时候直接调用这个函数
//读取文件进行处理是这样写的。
fs.readFile('/etc/passwd',function(err,data){
if(err) throw err;
console.log(data);
})
//node.js约定回调函数的第一个参数必须是错误对象err(如果没有错误,该参数就是null)
//原因是执行分成两段,在这两段之间抛出的错误程序无法捕捉,只能当做参数传入第二段
这里我有一个大胆的想法:是不是只要一个函数的第一个参数是err,都可以认为是回调函数呢?这个猜想暂时放在这里。哈哈
3.Promise的引入
其实回调函数本身没有什么问题,问题在于多个回调函数嵌套的话,比如读取第一个文件之后,再读取第二个文件,再读取第三个文件...读取第n个文件,这样下去会写很多个回调函数,gg。
因此,为了解决这个问题,引入了Promise,它不是一种新的语法功能,而是一种新的写法。例如:
var readFile = require('fs-readfile-promise');
readFile(fileA).then(function(data){
console.log(data.toString());
}).then(function(data){
return readFile(fileB);
}).then(function(data){
console.log(data.toString());
}).catch(function(err){
console.log(err);
})
上面代码存在的主要问题是代码冗余,原来的任务被Promise包装了一下,不管什么操作,一眼就能看出去都是一堆then,原来的语义变得很不清楚。
4.Generator函数的数据交换和错误处理
(1)这个函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因
(2)next方法返回值的value属性,是Generator函数向外输出数据,next方法可以接受参数,向Generator函数体内输入数据。
(3)Generator函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。
5.用Generator函数执行一个真实的异步任务
var fetch = require('node-fetch');
function* gen(){
var url = 'http://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}//上述代码中,Generator函数封装了一个异步操作,先读取一个远程的接口
//然后从JSON格式的数据解析信息,就像前面说的,这段代码非常像同步操作,只是加上了
//yield命令
var g = gen();
var result = g.next(); //fetch模块返回的是一个Promise对象
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
})
6.Thunk函数
(1)编译器的传名调用实现:将一个参数放在一个临时的函数中,然后将这个临时的函数传入函数体,这个临时的函数就是Thunk函数。
(2)JavaScript语言的Thunk函数:JavaScript语言是传值调用,它的Thunk函数含义有所不同。在JavaScript语言中,Thunk函数替换的不是表达式,而是多参数函数,它将其替换成单参数的版本,且只接受回调函数作为参数。
//简单的Thunk函数转换器
var thunk = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return function(callback){
args.push(callback);
return fn.apply(this,args);
}
}
}
//简单的Thunk函数转换器
var thunk = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return function(callback){
args.push(callback);
return fn.apply(this,args);
}
}
}
(3)Generator函数的流程管理
以读取文件为例子
用到的函数及作用:
1.Thunk函数,这个可以通过Thunkify模块,返回一个Thunk函数(并以回调函数作为它的参数)
2.Generator函数,这个函数主要用来封装两个或者两个以上的异步操作(通过yield命令后接异步操作)
,然后通过调用这个Generator函数获取到遍历器对象,然后这个对象调用next()方法来执行yield
命令之后的异步操作,执行成功之后会返回一个对象,这个对象的value的值也就是一个只接收回调函数
的一个Thunk函数,而这个回调函数主要用next方法将执行权交回给Generator函数,像这样下去,
可以继续执行Generator函数下面的异步操作。
var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);
var gen = function* (){
var r1 = yield readFile('/etc/fstab');
console.log(r1.toString());
var r2 = yield readFile('/etc/shells');
console.log(r2.toString());
}
//如何手动的执行上面这个Generator函数
var g = gen();
var result = g.next();
result.value(function(err,data){
if(err) throw err;
var r2 = g.next(data);
r2.value(function(err,data){
if(err) throw err;
g.next(data);
})
})
//可以方法上述Generator函数的执行过程是将同一个回调函数反复传入next方法的value属性。
//其实我们可以用递归来实现这个过程。
(4)Thunk函数的自动流程管理
Thunk函数真正的魅力在于可以自动执行Generator函数。
//下面通过一个run方法来实现Generator函数的自动执行,利用的主要是Thunk函数
function run(fn){
var gen = fn();
function next(err,data){
var result = gen.next(data);
if(result.done) return;
result.value(next);
}
next();
}
var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);
var gen = function* (){
var r1 = yield readFile('/etc/fstab');
console.log(r1.toString());
var r2 = yield readFile('/etc/shells');
console.log(r2.toString());
}
需要明白的几个点:
1.之所以能够自动执行Generator函数,是因为有Thunk函数的存在
2.Generator函数中的异步操作必须要是Thunk函数
3.在这个run方法中写这个next方法,作为Thunk函数参数的回调函数
4.在next方法中,继续将next方法传递给Thunk函数,实现递归,也就是继续自动执行
实现Generator函数自动执行的方案有:1.Thunk函数 2.Promise对象
(5)co模块:这个是一个小工具,用于Generator函数的自动执行
co模块可以让你不用编写Generator函数的执行器,Generator函数只要传入co函数就会自动执行
co函数会返回一个Promise对象,因此可以使用then方法添加回调函数。
co模块的原理
co模块其实就是一个异步操作的容器,它的自动执行只需要一种机制,当异步操作有了结果能够自动交回执行权。有两种方法:
1回调函数。将异步操作包装成Thunk函数,在回调函数中交回执行权
2.Promise对象。将异步操作包装成Promise对象,在then方法中交回执行权。
co模块的实质
将Thunk函数和Promise对象这两种自动执行机制,包装成了一个模块。使用co模块的前提条件是,Generator函数的yield命令只能是Thunk函数或者是Promise对象
var fs = require('fs');
var readFile = function(fileName){
return new Promise(function(resolve,reject){
fs.readFile(fileName,function(error,data){
if(error) reject(error);
resolve(data);
})
})
}
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
}
var g = gen();
g.next().value.then(function(data){
g.next(data).value.then(function(data){
g.next(data);
})
})//手动执行也就是不断的添加回调函数
//下面自己写一个自动执行器
function run(gen){
var g = gen();
function next(data){
var result = g.next(data);
if(result.done) return;
result.value.then(function(data){
next(data);
})
}
next();
}
co模块可以处理并发的异步操作
co支持并发的异步操作,即允许某些操作同时进行,等到他们全部完成才进行下一步
这时要把并发的操作都放在数组或者对象里面,跟在yield语句后面
//数组的写法
co(function* (){
var res = yield [
Promise.resolve(1);
Promise.resolve(2);
];
console.log(res);
}).catch(onerror);
//对象的写法
co(function* (){
var res = yield {
1:Promise.resolve(1);
2:Promise.resolve(2);
};
console.log(res);
}).catch(onerror);
co(function* (){
var values = [n1,n2,n3];
yield values.map(somethingAsync);
}) //这里允许并发3个somethingAsync异步操作,等到他们全部完成才会进行下一步
function* somethingAsync(x){
return y;
}
ES6的异步操作的更多相关文章
- ES6 Promise 异步操作
最近越来越喜欢与大家进行资源分享了,并且及时的同步到自己的园子内,为什么呢? 一.小插曲(气氛搞起) 在上个月末,由于领导的高度重视(haha,这个高度是有多高呢,185就好了),走进了公司骨干员工的 ...
- Promise原理探究及实现
前言 作为ES6处理异步操作的新规范,Promise一经出现就广受欢迎.面试中也是如此,当然此时对前端的要求就不仅仅局限会用这个阶段了.下面就一起看下Promise相关的内容. Promise用法及实 ...
- ES6语法(3)—— 用promise()对象优雅的解决异步操作
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果. ...
- ES6学习笔记七:生成器与异步操作
一:Generator Generator 函数是一个普通函数,但是有两个特征.一是,function关键字与函数名之间有一个星号:二是,函数体内部使用yield表达式,输出不同的内部状态. 执行 G ...
- es6异步操作
异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. ES6 诞生以前,异步编程的方法,大概有下面四种. 回调函数 事件监听 发 ...
- ES6异步操作之Promise
一直以来觉得异步操作在我心头像一团迷雾,可是它重要到我们非学不可,那就把它的面纱解开吧. ES6 诞生以前,异步编程的方法,大概有下面四种. 回调函数 事件监听 发布/订阅 Promise 对象 异步 ...
- ES6学习路上的小学生,promise处理异步操作,简易原始起步之用。先能用,再深究!
ES6的promise对象,让我们更容易的处理这样的需求:执行完一个方法以后,再去执行下一个方法. 理解尚浅之时,先用于项目之中. var promise1 = new Promise(functio ...
- ES6学习笔记(四):异步操作
Promise Promise三种状态 pending.resolved.rejected 使用语法 var promis = new Promise(function(resolve,reject) ...
- ES6——异步操作之Promise
基本概念: Promise : 是 ES6 中新增的异步编程解决方案,提现在代码中他是一个对象 可以通过Promise构造函数来实例化. -new Promise(cb) ===> 实例的基本使 ...
随机推荐
- upupw注入by pass
http:' and updatexml(null,concat(0x5c,(/*!00000select SCHEMA_name*/from/*!information_schema*/.schem ...
- Django 1.10中文文档-第一个应用Part3-视图和模板
本教程上接Django 1.10中文文档-第一个应用Part2-模型和管理站点.我们将继续开发网页投票这个应用,主要讲如何创建一个对用户开放的界面. 概览 视图是Django应用中的一“类”网页,它通 ...
- Qualcomm platform, the commonly used parameters of charger and battery in device tree file
Platform MSM8917 PM8937 PMI8940 Parameters 1 battery charging voltage : qcom,float-voltage-mv = < ...
- python实战===百度文字识别sdk
http://ai.baidu.com/docs#/OCR-Python-SDK/top
- Git 常用命令速查表(图文+表格)【转】
转自:http://www.jb51.net/article/55442.htm 一. Git 常用命令速查 git branch 查看本地所有分支git status 查看当前状态 git comm ...
- Ubuntu终端里面显示路径名称太长,怎么设置变短【转】
转自:http://blog.csdn.net/id19870510/article/details/8276914 $: sudo vi ~/.bashrc 这个文件记录了用户终端配置 找到 if ...
- PXC 避免加入集群时发生SST
环境 现有集群节点: 192.168.99.210:3101 新加入节点: 192.168.99.211:3101 通过xtrabackup备份还原实例,并通过同步方式追数据: 已有节点情况: roo ...
- 使用UpdatePanel时FileUpload失效的问题
出处:http://www.cnblogs.com/caicainiao/archive/2010/12/08/1900377.html 1.使用UpdatePanel后,FileUpload的Has ...
- Docker壳的配置笔记
docker 就是一个运行容器,在这个盒子里,他的端口,路径可以虚拟到另一个实际的磁盘上,运行空间独立,更安全! yum install -y docker docker-client service ...
- #error This file was generated by a newer version of protoc
pattern@pattern89:/raid0/workspace/houjun/caffe-ssd$ sudo make all -j8PROTOC src/caffe/proto/caffe.p ...