CNode

能讲清楚这段代码的不是大牛,就是即将迈向大牛的小牛!

问答
Ddlyt发布于9 年前最后回复9 年前21 回复6595 浏览0 收藏
co.wrap = function(gen) {
    var idt = gen(resume)
    function resume() {
        var args = arguments
        process.nextTick(function() {
            var obj = idt.next(args).value
            if (obj && isPromise(obj))
                obj.then(
                  (res) => {
                    resume(null, res)
                  },
                  (err) => resume(err)
                )
        })
    }
    return resume
}
co.run = function(gen) {
    co.wrap(gen)()
}
co.run(function * ($) {
	// yield
})
function isPromise(obj) {
    return 'function' == typeof obj.then;
}

对应这句代码我不是很理解: resume(null, res) 望指教

原来我不理解是因为: 不懂为什么要递归呢? 是为了继续运行生成器函数,直到返回 Object { value: undefined, done: true } resume(null, res)传的参数是干什么用的呢? 实际上是将结果传回去,类似这个

function* gen() {
  while(true) {
    var value = yield null;
    console.log(value);
  }
}

var g = gen();
g.next(1); 
// "{ value: null, done: false }"
g.next(2); 
// "{ value: null, done: false }"
// 2

等我想好了,我会告诉大家使用process.nextTick( )的意义。

查看回复

回复 (21)

I
im-here#1·9 年前

估计就相当于callback吧,即callback(null,res),因为没有error所以给了null了 不要问为什么,我也是猜的

D
dlyt#2·9 年前
引用 im-here估计就相当于`callback吧,即callback(null,res),因为没有error所以给了null`了 不要问为什么,我也是猜的

@imhered 没想问为什么,因为你根本没讲到点上。原谅我说话很直。。。

G
gjc9620#3·9 年前
const co = {};
  co.wrap = function(gen) {
    var idt = gen(resume) //idt  是个迭代器
    function resume() {
      var args = arguments //执行结果
      process.nextTick(function() { //循坏迭代
        var obj = idt.next(args).value
        if (obj && isPromise(obj) //只能接受Primse对象
          obj.then(
            (res) => {
              resume(null, res) //异步结束了 递归调用resume(执行结果)  resume又会idt.next() 执行下一步
            },
            (err) => resume(err)
          )
      }, 0)
    }
    return resume
  }
  co.run = function(gen) {
    co.wrap(gen)()
  }
  
  co.run(function * ($) {
    // yield
	
	//idt.next(args) args = [ null, 1]
    const num1 = yield new Promise((resolve, reject) => {
      setTimeout(()=>{
        resolve(1)
      }, 2E3);
    });
	//num2 = [null, 2]
    const num2 = yield new Promise((resolve, reject) => {
      setTimeout(()=>{
        resolve(2)
      }, 2E3);
    });
    console.log(num1[1] + num2[1]);
  })

话说回来 这种不是promise对象就不继续执行了真的大丈夫? 而且process.nextTick 好像没什么意义

O
orangebook#4·9 年前

tj封装generator的co 库,不是很明白。Generator和Promise一样解决回调问题的 PS:这个有点标题党了,回答该问题只是对代码的探讨

D
dlyt#5·9 年前
引用 orangebooktj封装generator的co 库,不是很明白。Generator和Promise一样解决回调问题的 PS:这个有点标题党了,回答该问题只是对代码的探讨

@orangebook 该段代码涉及了闭包、 process.nextTick( )、递归、Generator、Promise等等。你如果还要说我标题党,我认了。

Z
zhuscat#6·9 年前

问题是,co 的源码不是这个样子的吧。。。

M
magicdawn#7·9 年前

idt.next(args) 需要 try/catch

D
dlyt#8·9 年前
引用 gjc9620话说回来 这种不是promise对象就不继续执行了真的大丈夫? 而且process.nextTick 好像没什么意义

@gjc9620 arguments 不是执行结果 arguments是一个类似数组的对象,对应于传递给函数的参数。 例子:

function(arg1, arg2, arg3) {
  var args = arguments
  console.log(args[0])  // arg1
}
D
dlyt#9·9 年前
引用 magicdawnidt.next(args) 需要 try/catch

@magicdawn 为什么啊 在这里捕获不行么?

co.run(function * ($) {
	try{
		// yield
	} catch(e) {}
})
H
hyj1991#10·9 年前
co.run = function(gen) {
    co.wrap(gen)()
}

这样一写,

var args = arguments

等于没用了...

D
dlyt#11·9 年前
引用 hyj1991这样一写, 等于没用了...

@hyj1991 args对应的是resume(null, res)里面的参数,为什么没用呢?

Z
zxc122333#12·9 年前

这不是tj的co吧,这代码显然要var [err,result] = yield xxx()这样来接收返回结果

G
gjc9620#13·9 年前
D
dlyt#15·9 年前
引用 gjc9620@dlyt 是执行结果啊 所以num1 才会是[null ,1] 上一次异步执行的结果啊

@gjc9620 你这么说也可以,这个场景是的,但换个场景就不是了。 我上面说的也有问题。 args在resume()第一次执行的时候是{} 你能说执行结果是这个么?显然是不严谨的。 它就是一个类似数组的对象,用于传递给函数的参数。在这里用于获取resume函数的参数。而这个参数是用来传递结果的。

Z
zy445566#16·9 年前

@dlyt 那我这道题,楼主试试讲个原理?我肯定不输出hello @hyj1991 是否也有兴趣?

var a=[{test:"test"}];
var b=a;
b.push(a);
while(b[1])
{
    b=b[1];
}
console .log("hello");
Y
yyrdl#17·9 年前
G
gjc9620#20·9 年前
引用 yyrdl@gjc9620 避免伪异步造成异常 https://github.com/yyrdl/zco/blob/master/index.js L160 160行这儿的注释

@yyrdl co.run(function * ($) {

$(anything) })

假如没有process.nextTick 这样写会 enerator is already running(当然。。) so 为什么要把resume 传进去。。 什么时候才会用到$()?

Y
yyrdl#21·9 年前
引用 gjc9620@yyrdl co.run(function ($) { $(anything) }) 假如没有process.nextTick 这样写会 enerator is already runnin...

@gjc9620 哈哈,比如:


co.run(function*($){
     let [err,files]=yield fs.readFile("./anyfile.txt",$);
})

欢迎试用 zco full feature ,我最喜欢的是defer 和摆脱了Promise, 每次写Promise都很不爽,感觉不够直接

参与回复
登录后即可参与回复。登录