能讲清楚这段代码的不是大牛,就是即将迈向大牛的小牛!
发布于 7 年前 作者 dlyt 5067 次浏览 来自 问答
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 回复

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

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

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 好像没什么意义

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

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

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

idt.next(args) 需要 try/catch

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

function(arg1, arg2, arg3) {
  var args = arguments
  console.log(args[0])  // arg1
}

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

co.run(function * ($) {
	try{
		// yield
	} catch(e) {}
})
co.run = function(gen) {
    co.wrap(gen)()
}

这样一写,

var args = arguments

等于没用了…

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

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

@dlyt 是执行结果啊 所以num1 才会是[null ,1] 上一次异步执行的结果啊

@zxc122333 的确这么接收

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

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

var a=[{test:"test"}];
var b=a;
b.push(a);
while(b[1])
{
    b=b[1];
}
console .log("hello");

@gjc9620 process.nextTick 是有意义的,但这里滥用了。PS : Promise 看着蛋疼

@yyrdl process.nextTick 有何意义?

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

$(anything) })

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

@gjc9620 哈哈,比如:


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

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

回到顶部