co源码
co模块整体包括三部分
对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种;
将几种不同的参数类型转换为promise
递归执行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源码的更多相关文章
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- C# ini文件操作【源码下载】
介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 从源码看Azkaban作业流下发过程
上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- SDWebImage源码解读之SDWebImageDownloaderOperation
第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
随机推荐
- [Python自学] day-21 (1) (请求信息、html模板继承与导入、自定义模板函数、自定义分页)
一.路由映射的参数 1.映射的一般使用 在app/urls.py中,我们定义URL与视图函数之间的映射: from django.contrib import admin from django.ur ...
- JS栈内存与堆内存
㈠JavaScript变量 ⒈分类 ⑴JavaScript中的变量分为基本类型和引用类型. ⑵基本类型就是保存在栈内存中的简单数据段. ⑶引用类型指的是那些保存在堆内存中的对象. ⒉基本类型 基本类 ...
- Luogu P2516 [HAOI2010]最长公共子序列 DP
首先$LIS$显然:$f[i][j]=max(f[i][j-1],f[i-1][j],(a[i]==b[j])*f[i-1][j-1])$ 考虑如何转移数量: 首先,不管$a[i]$是否等于$b[j] ...
- SQL Server 基础:ADO.NET
序言 Connection 主要提供与数据库的连接功能 Command 用于返回数据.修改数据.运行存储过程以及发送或检索参数信息的数据库命令 CommandType 获取或设置Command对象要执 ...
- Visual Studio 2019 激活
Visual Studio 2019 Enterprise 企业版:BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional 专业版: ...
- Java的23种设计模式<一>
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...
- 【Redis 向Redis中批量导入mysql中的数据(亲自测试)】
转自:https://blog.csdn.net/kenianni/article/details/84910638 有改动,仅供个人学习 问题提出:缓存的冷启动问题 应用系统新版本上线,这时候 re ...
- 使用git Bash Here 绑定账号密码错误后 无法自动重新绑定
新安装的git 要打开gitbash 运行下面两个命令:1 git config --global user.name "Your Name"2 git config --glob ...
- 理解Cookie和Session
HTTP 无状态协议 HTTP 本身是一个无状态的连接协议,无状态的意思是:每条请求/响应都是独立进行的,服务端每处理完一个客户端的请求之后就会断开连接,并且每条请求/响应与其之前(或之后)的请求/响 ...
- js最简洁的时间对象转成时间字符串的方法
getTimestr(val){ let temp = val.toLocaleString() if(temp.match(/[\u4e00-\u9fa5]/g)[0]=="上" ...