一个generator自动执行器

一个generator自动执行器

最近看 redux-saga的源代码, 作者写的yield执行器代码非常不错,详细的分析一下

  1. 支持异常处理
  2. 支持thunk
  3. 支持promose
  4. 支持常量值

** 利用的根本: **

  1. 如果一个promise (假设A)的resolve函数传递的是一个promise(假设B)对象,那么这 个promiseA对象是无法立即确定状态为Onfulfilled的,必须先等等promiseB的状态确定后,然后将promiseB的内部value,传递给promiseA的resove. 即再执行一遍promiseA的resolve,只是这时候的参数值不为promise对象,而是一个具体值, 所以此时promiseA的状态获取,value为从promiseB传递过来
  2. 扩展: 每个then里面的onfulfilled函数的返回值,都直接作为.then这个函数本身返回的promise对象的resolve参数,其中如果返回值为promise的话,那么按照1的规则
function runGenerator(generatorFUN, initialValue) {
  const generator = generatorFUN(initialValue);
  iterate(generator);

  function iterate(generator) {
    step();
    // step传递的值为  上一个yield右表达式的"求出的值",isError标记上一个yield是否发生异常
    //利用arg 赋值给上一个yield的左表达式值,并返回下一个yield右表达式的值
    function step(arg, isError) {

      //如果上一个next执行完后发送错误了,那么就抛出一个异常
      //由于从上一个yield左边表达式开始执行,所以恰好处理异常的话,就是在上一个yield那里捕获异常
                            
      //这里的arg的值可能有几种情况获取
      /**
       * 
       * 一种是 yield new Promise()
       * 一种是 yield () => {return value}
       * 一种是 yield () => {return new Promise}
       * 一种是 yield value 那么arg就直接是value
       * 
       * 而且arg的值, 不能直接是promise, 而是promise执行完成后,确实的内部的value(即传递给then注册的值)
       * 
       * 如何做到这一点呢? 下面再说
       */
      const {value: express, done} = isError ? generator.throw(arg) : generator.next(arg); 

      let response;
      if (!done) {  //一定要有 不然无限递归
        //由迭代器的知识 我们知道 express 是yield右侧的值
        if (typeof express === 'function') {
          response = express();  //response 可能为 promise  或者value
        } else {
          response = express;    //这里response可能为promise 或者value
        }

        //要求,如果为promise, 那么arg的值为 promise确实状态后的value值,如果为value
        // 那么就直接设置为value----你想到什么了么?
        //再看看我上面说的根本,promise的巧妙之处

        //如果一个promise A的resolve传递的是 promise B对象,那么这个promise A对象并不一定就
        //里面是onfulfilled状态,而是根据 promise B对象的状态决定,如果promiseB 对象为reject,
        // 那么promise A对象也是reject,resovle也同理,而且会把promiseB 对象的value传递给 promiseA
        //的 resolve (promise B状态确定后,重新执行一遍 promiseA的promise resolve 只是参数value不为promise了)

        //这句话是非常巧妙的,respone可能为 value 或者 promise对象
        //Promise.resolve 不一定为 Onfulfilled 状态的,得看 response
        //而且response执行完成后的值 可以直接传递给 Promise.resolve 的resolve, 即then 里面的next参数
        //如果respone为 reject的话 执行后面的 err => next, true

        Promise.resolve(response).then(step, err => step(err, true));
      }
    }
  }
}

//删除注释后

function runGenerator(generatorFUN, initialValue) {
  const generator = generatorFUN(initialValue);
  iterate(generator);

  function iterate(generator) {
    step();
    function step(arg, isError) {
      const {value: express, done} = isError ? generator.throw(arg) : generator.next(arg); 
      let response;
      if (!done) {
        if (typeof express === 'function') {
          response = express();  
        } else {
          response = express;    
        }
        Promise.resolve(response).then(step, err => step(err, true));
      }
    }
  }
}

测试一下

function* gen1() {
  yield console.log(1);
  yield console.log(2);
  yield console.log(3);
}
runGenerator(gen1);
function* gen2() {
  var value1 = yield Promise.resolve('promise');  //直接返回promise
  console.log(value1);

  var value2 = yield () => Promise.resolve('thunk prommise')  //thunk里面返回promise
  console.log(value2);

  var value3 = yield "string type";
  console.log(value3);

  var value4 = yield () => "thunk string type"
  console.log(value4);
}

 runGenerator(gen2);

异常情况 可以在看看上面的异常处理流程 是由谁抛的 为啥我们能接收到 根据什么理由抛的异常

function* gen3() {
  try {
    var value1 = yield new Promise((resolve, reject) => setTimeout(reject, 0, 'reject error'));
  } catch (error) {
    console.log(error);
  }
  var value2 = yield 3;
  console.log(value2);
}

runGenerator(gen3);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容