co模块整体包括三部分

  1. 对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种;

  2. 将几种不同的参数类型转换为promise

  3. 递归执行promise

     module.exports = co['default'] = co.co = co;
    let slice = [].slice; // 多次用到,所以定义成变量; 原文是Array.prototype.slice // 1. 对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种; /**
    * 判断是否为对象
    * 任何数据类型的constructor属性返回创建该对象的函数的引用,实例的constructor属性指向其构造函数,
    */
    function isObject(obj) {
    return obj.constructor === Object;
    } /**
    * 是否promise
    * promise具有.then方法,.catch方法
    */
    function isPromise(obj) {
    return 'function' === typeof obj.then; //也可以用 obj.constructor === Promise
    } /**
    * 是否generator对象,
    * generator具有next,throw,return方法
    */
    function isGenerator(obj) {
    return 'function' === typeof obj.next() && 'function' === typeof obj.throw() && 'function' === typeof obj.return();
    } /**
    * generator的constructor的name为GeneratorFunction,displayName(非标准)如果设置也为* GeneratorFunction,
    * display相关参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/displayName
    *【注意】generator的constructor !== GeneratorFunction , 参考自这里https://blog.csdn.net/sinat_30552885/article/details/85247120
    */
    function isGeneratorFunction(obj) {
    let constructor = obj.constructor;
    if ( !constructor ) return false;
    if ( constructor.name === 'GeneratorFunction' || constructor.displayName === 'GeneratorFunction') return true;
    return isGenerator(obj);
    } // 2. 将几种不同的参数类型转换为promise // 总括
    function toPromise(obj) {
    if (!obj) return obj;
    if ( isPromise(obj) ) return obj;
    if ( isGenerator(obj) || isGeneratorFunction(obj) ) return co.call(this, obj); // co的入参接收promise或者generator,因此如果是generator,则直接调用一遍co;
    if ( 'function' === typeof obj) return thunkToPromise.call(this, obj);
    if ( Array.isArray(obj) ) return arrayToPromise.call(this, obj);
    if ( isObject(obj) ) return objToPromise.call(this, obj);
    return obj;
    } /**
    * thunk => promise
    */
    function thunkToPromise(fn) {
    let ctx = this;
    return new Promise(function(resolve, reject) {
    fn.call(ctx, function(err, res) {
    if ( err ) reject(err);
    if ( arguments.length > 2) res = slice.call(arguments,1);
    resolve(res);
    })
    })
    } /**
    * arr => promise
    * 将数组的每一元素变成promise,然后放入到promise.all里统一存储
    */
    function arrayToPromise(arr) {
    return Promise.all(arr.map(toPromise, this));
    } /**
    * obj => promise;
    * obj.constructor 返回创建该对象的函数的引用
    */
    function objToPromise(obj) {
    let results = new obj.constructor();
    let promises = [];
    let keys = Object.keys(obj);
    for ( let i = 0; i < keys.length; i++ ) {
    let key = keys[i];
    let promise = toPromise(this, obj[key]);
    if ( promise && isPromise(promise) ) {
    defer(promise, key);
    } else {
    results[key] = obj[key];
    }
    }
    return Promise.all(promises).then(function() {
    return results;
    })
    function defer(promise, key) {
    promises.push(promise.then(function(res) {
    results[key] = res;
    }))
    }
    } // 3. 递归执行promise /**
    *
    * @param {*} fn 入参是一个promise或者generator
    * @return Promise;
    */
    function co(gen) {
    let ctx = this;
    let args = slice.call(arguments, 1);
    return new Promise(function(resolve, reject) {
    if ( typeof gen === 'function') gen = gen.apply(ctx, args);
    if ( !gen || typeof gen !== 'function' ) resolve(gen);
    onFulfilled();
    function onFulfilled() {
    let ret;
    try {
    ret = gen.next();
    } catch (e) {
    return reject(e);
    }
    next(ret);
    }
    function onRejected() {
    let ret;
    try {
    ret = gen.throw();
    } catch (e) {
    return reject(e)
    }
    next(ret);
    }
    function next(ret) {
    if ( ret.done ) return resolve(ret.value);
    let value = toPromise.call(this, ret.value);
    if ( value && isPromise(value)) return value.then(onFulfilled, onRejected);
    } return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, but the following object was passed: "' + String(ret.value) + '"'));
    })
    } co.wrapper = function(fn) {
    createPromise.__generatorFunction__ = fn;
    return createPromise;
    function createPromise() {
    return co.call(this, fn.apply(this,arguments))
    }
    }

co源码的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. C# ini文件操作【源码下载】

    介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...

  3. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  4. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  6. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  7. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  8. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  9. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  10. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

随机推荐

  1. redistempalate的超时设置的操作更新

    redistempalate的超时设置时,一定要每次用set写入时,更新超时,默认是不会自动更新的. 例如: int tempTime = this.redisTemplate.getExpire(& ...

  2. 步骤五 · 4-9 解决getElementsByClassName()兼容性 未解决

    前端零基础入门 2019版 / 步骤五 · 4-9 解决getElementsByClassName()兼容性

  3. Elasticsearch7.1中文文档-第一章-入门

    安装openjdk wget --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-secur ...

  4. 自动上传本地图片和word图片(word图片需使用从word粘贴功能)

    在之前在工作中遇到在富文本编辑器中粘贴图片不能展示的问题,于是各种网上扒拉,终于找到解决方案,在这里感谢一下知乎中众大神以及TheViper. 通过知乎提供的思路找到粘贴的原理,通过TheViper找 ...

  5. DbFunctions 作为 LINQ to Entities 查询的一部分使用时,此方法调用规范 CreateDateTime EDM 函数以创建新的 DateTime 对象。

    DbFunctions.CreateDateTime CreateDateTime(year, month,day,hour,minute,second)

  6. python 列表切片之负数的含义代码示例

    a = list(range(10)) print(a[::]) #复制一个列表 print(a[::2]) #每隔2个取一次 print(a[::3]) #每隔3个取一次 print(a[::-1] ...

  7. 数据结构-用C++实现一个二叉树,递归方法中序遍历

    1:二叉排序树,又称二叉树.其定义为:二叉排序树或者空树,或者是满足如下性质的二叉树. (1)若它的左子树非空,则左子树上所有节点的值均小于根节点的值. (2)若它的右子树非空,则右子树上所有节点的值 ...

  8. Leetcode题目169.求众数(简单)

    题目描述: 给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在众数. 示例 1: 输入: [3,2,3] ...

  9. SpringCloud-Config通过Java访问URL对敏感词加密解密

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  10. Python驱动Headless Chrome

    Headelss 比Headed的浏览器在内存消耗,运行时间,CPU占用都更具优势 from selenium import webdriverfrom selenium.webdriver.chro ...