zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Es6系列之深入generator2

ES6 系列 深入
2023-09-14 09:01:05 时间
第一种方案

利用generator来调用异步主要是为了解决异常调用嵌套的问题,下面先模拟一个嵌套调用的异步过程.

functin request(delay, callback){

 setTimeout(function(){

 callback({

 name: feenan

 }, +delay);

request(1000, function(msg){

 console.log(msg);

 request(2000, function(msg){

 console.log(msg);

然后我们来看看怎么用generator来同步处理这里请求,首先我们来定义生成器函数.

function* main(){

 var result = yield request(1000);

 console.log(result);

 var result1 = yield request(2000);

 console.log(result);

var it = main();

此时我们需要改进下request函数.

functin request(delay){

 setTimeout(function(){

 it.next({

 name: feenan

 }, +delay);

注意上面的异步函数里增加了it.next,这样就能保证回调的值能传入main函数里去.因为next函数的参数是上一次yield表达式的值,第一次给next传参默认会忽略.

上面的方案虽然实现了异步方法的扁平化处理,但是有些缺点

异步方法深度依赖生成器实例,倒致不能重用 不能处理多个异步同时调用的情况

来看看第二种方案是怎么解决这种问题的?

第二种方案promise

虽然上面的方案可以实现异步调用的扁平化处理,但是仍然存在问题,下面我们来用Promise来实现一个更好的扁平化方案

Promise是es6提供的原生支持promise规范的类,提供有then,all,catch方法.我们先来改装下request方法

function request(id, delay){

 return new Promise(function(resolve, reject){

 setTimeout(function(){

 if(id == 1) reject(new Error(new Error!));

 resolve({

 name: feenan,

 id: id

 }, +delay);

Promise通过new一个实例,传入待执行的异步方法,内部利用resolve,reject来导出成功和失败的信息.可以看出这个方法跟generator是完全没关系的,已经解藕了,而且也可以重用在别的类库里,然后我们再来定义我们的生成器函数.

function* main(){

 try{

 var result = yield request(1, 1000);

 if(result.name == feenan){

 var result1 = yield request(2, 2000);

 return done!;

 }catch(err){

 console.log(err);

此处的try...catch是用来捕获里面异步方法的异常的,通过throw方法,这个等会儿会讲到.

也许大家会看到,上面的main方法的yield会返回一个promise对象,但是result应该会接收到异步回调结果的,这里我们应该怎么处理呢?对,我们还需要定义一个运行生成器函数的函数.

function runGenerator(g){

 return new Promise(function(resolve, reject){

 var it = g(), ret;

 (function iterate(val){

 ret = it.next(val);

 if(!ret.done){

 // 检查是否是promise对象

 if(then in ret.value){

 ret.value.then(iterate).catch(function(err){

 it.throw(err);

 }else{

 setTimeout(function(){

 iterate(ret.value);

 }, 0)

 }else{

 resolve(ret);

 })();

代码看起来有点复杂,我一一来解释.

首先函数本身返回一个promise对象用来处理生成器函数返回值,内部定义了一个iterate立即执行函数,runGenerator内部会先生成一个迭代器名为it,参数即是生成器函数,然后iterate会先调用it.next传递参数,默认第一次参数会忽略,然后检查it.next的返回值,这个返回值属性格式默认为{value: , done: },value为yield后表达式的返回值,done代表迭代是否完毕,因为yield后面返回的是一个promise对象,所以检查ret.value是否是一个promise对象,是的话则调用then方法传递当前iterate本身,这就是运行函数的奥妙所在,因为此时会把异步回调的结果传递给下一次的it.next,这样main函数里的result就能接收到异步回调的结果了,然后就是不断重复上面的步骤直到执行完毕,利用resolve向外抛出生成器函数的返回值,我们来看看运行的样子

runGenerator(main).then(msg){

 console.log(msg); // = done!

另外我们还可以利用promise.all方法达到异步同时调用多个方法的功能,此处只需要定义一个多个异步调用方法,promise.all会调用多个promise对象最终只返回一个promise对象

// 包装多个异常请求成功之后返回一个新的promise

// 利用Promise.all类方法

function requestAll(){

 var promises = [1000, 2000, 3000].map(function(v, k){

 return new Promise(function(resolve, reject){

 setTimeout(function(){

 resolve({

 name: feenan,

 id: v

 }, v);

 return Promise.all(promises);

然后我们修改main函数里的request即可

// var result = yield request(1, 1000);

var result = yield requestAll(); 

此处需要注意下,上面的result是一个数组,里面每项为单个promise对象的返回值

可以看到利用promise+generator可以完美的原生实现异步调用扁平化,这对复杂业务逻辑的实现是相当好的.

下面我再说说es7里对于异步调用方法的更进一步的完美支持,而且代码量更少

第三种方案async

es7里提供了async语法来定义异步函数,配合await关键字轻易就能实现上面的功能

function request(id, delay){

 return new Promise(function(resolve, reject){

 setTimeout(function(){

 if(id == 1) reject(new Error(new Error!));

 resolve({

 name: feenan,

 id: id

 }, +delay);


await告诉引擎需要等后面的异步执行完成之后才能执行下面的语句,这是原生支持的,不需要像上面那样定义运行函数来一步一步执行.

await后面必须是一个promise对象实例,所以这里也的用上promise特性.

不过async语法成为标准之路还很遥远,庆幸的是traceur支持这个语法.

最后我觉的还是promise和generator是完美解决异步调用的方案,以上所有实例都可以通过traceur命令来运行.


浅析-ES6 后端项目搭建完毕,接下来就是前端页面了。不过在这之前需要一些准备工作。我们需要学习ES6的语法标准。
浅谈一下ES6的提升 es6的提升 在es6之前,我们定义定义变量的时候,只能使用var关键字来定变量,这样有一个问题,var定义的变量会成为全局变量。
一篇文章带你学会整个ES6 ES 全称 EcmaScript,是脚本语言的 规范 ,而平时经常编写的 JavaScript ,是 EcmsScript 的 一种实现 ,所以 ES 新特性其实是指 JavaScript 的新特性 。
3DES数据加密算法 3DES数据加密算法是一种可逆的对称加密算法,也称三重数据加密算法(英语:Triple Data Encryption Algorithm,缩写为TDEA,Triple DEA),或称3DES(Triple DES),它是一种为了替代原先DES而建立的数据加密标准。