- const gen = function * () {
- let index = 0;
- while (index < 3) yield index++;
- return 'All done.'
- };
- const g = gen();
- console.log(g.constructor); // output: GeneratorFunction {}
- console.log(g.next()); // output: { value: 0, done: false }
- console.log(g.next()); // output: { value: 1, done: false }
- console.log(g.next()); // output: { value: 2, done: false }
- console.log(g.next()); // output: { value: 'All done.', done: true }
- console.log(g.next()); // output: { value: undefined, done: true }
- const Koa = require('koa');
- const app = new Koa();
- app.use(async (ctx, next) => {
- const start = Date.now();
- await next();
- const ms = Date.now() - start;
- console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
- });
- const Koa = require('koa');
- const app = new Koa();
- // response
- app.use(ctx = >{
- ctx.body = 'Hello Koa';
- });
- app.listen(3000);
- const Koa = require('koa');
- const app = new Koa();
- const co = require('co');
- // response
- app.use(co.wrap(function * (ctx, next) {
- yield next();
- // yield someAyncOperation;
- // ...
- ctx.body = 'co';
- }));
- app.listen(3000);
- // co的源码
- return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
- + 'but the following object was passed: "' + String(ret.value) + '"'));
- // 这里模拟一个generator函数调用
- const co = require('co');
- co(gen).then(data = >{
- // output: then: ALL Done.
- console.log('then: ' + data);
- });
- function * gen() {
- let data1 = yield pro1();
- // output: pro1 had resolved, data1 = I am promise1
- console.log('pro1 had resolved, data1 = ' + data1);
- let data2 = yield pro2();
- // output: pro2 had resolved, data2 = I am promise2
- console.log('pro2 had resolved, data2 = ' + data2);
- return 'ALL Done.'
- }
- function pro1() {
- return new Promise((resolve, reject) = >{
- setTimeout(resolve, 2000, 'I am promise1');
- });
- }
- function pro2() {
- return new Promise((resolve, reject) = >{
- setTimeout(resolve, 1000, 'I am promise2');
- });
- }
- function co(gen) {
- // 保存当前的执行环境
- var ctx = this;
- // 切割出函数调用时传递的参数
- var args = slice.call(arguments, 1)
- // we wrap everything in a promise to avoid promise chaining,
- // which leads to memory leak errors.
- // see https://github.com/tj/co/issues/180
- // 返回一个Promise实例
- return new Promise(function(resolve, reject) {
- // 如果gen是一个函数,则返回一个新的gen函数的副本,
- // 里面绑定了this的指向,即ctx
- if (typeof gen === 'function') gen = gen.apply(ctx, args);
- // 如果gen不存在或者gen.next不是一个函数
- // 就说明gen已经调用完成,
- // 那么直接可以resolve(gen),返回Promise
- if (!gen || typeof gen.next !== 'function') return resolve(gen);
- // 首次调用gen.next()函数,假如存在的话
- onFulfilled();
- /**
- * @param {Mixed} res
- * @return {Promise}
- * @api private
- */
- function onFulfilled(res) {
- var ret;
- try {
- // 尝试着获取下一个yield后面代码执行后返回的值
- ret = gen.next(res);
- } catch(e) {
- return reject(e);
- }
- // 处理结果
- next(ret);
- }
- /**
- * @param {Error} err
- * @return {Promise}
- * @api private
- */
- function onRejected(err) {
- var ret;
- try {
- // 尝试抛出错误
- ret = gen.
- throw (err);
- } catch(e) {
- return reject(e);
- }
- // 处理结果
- next(ret);
- }
- /**
- * Get the next value in the generator,
- * return a promise.
- *
- * @param {Object} ret
- * @return {Promise}
- * @api private
- */
- // 这个next()函数是最为关键的一部分,
- // 里面几乎包含了generator自动调用实现的核心
- function next(ret) {
- // 如果ret.done === true,
- // 证明generator函数已经执行完毕
- // 即已经返回了值
- if (ret.done) return resolve(ret.value);
- // 把ret.value转换成Promise对象继续调用
- var value = toPromise.call(ctx, ret.value);
- // 如果存在,则把控制权交给onFulfilled和onRejected,
- // 实现递归调用
- 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) + '"'));
- }
- });
- }
- function toPromise(obj) {
- if (!obj) return obj;
- if (isPromise(obj)) return obj;
- if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
- if ('function' == typeof obj) return thunkToPromise.call(this, obj);
- if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
- if (isObject(obj)) return objectToPromise.call(this, obj);
- return obj;
- }
- function objectToPromise(obj) {
- // 获取一个和传入的对象一样构造器的对象
- var results = new obj.constructor();
- // 获取对象的所有可以遍历的key
- var keys = Object.keys(obj);
- var promises = [];
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
- // 对于数组的每一个项都调用一次toPromise方法,变成Promise对象
- var promise = toPromise.call(this, obj[key]);
- // 如果里面是Promise对象的话,则取出e里面resolved后的值
- if (promise && isPromise(promise)) defer(promise, key);
- else results[key] = obj[key];
- }
- // 并行,按顺序返回结果,返回一个数组
- return Promise.all(promises).then(function() {
- return results;
- });
- // 根据key来获取Promise实例resolved后的结果,
- // 从而push进结果数组results中
- function defer(promise, key) {
- // predefine the key in the result
- results[key] = undefined;
- promises.push(promise.then(function(res) {
- results[key] = res;
- }));
- }
- }
- // my-co.js
- module.exports = my - co;
- let my - co = function(gen) {
- // gen是一个具有Promise的生成器函数
- const g = gen(); // 迭代器
- // 首次调用next
- next();
- function next(val) {
- let ret = g.next(val); // 调用ret
- if (ret.done) {
- return ret.value;
- }
- if (ret && 'function' === typeof ret.value.then) {
- ret.value.then((data) = >{
- // 继续循环下去
- return next(data); // promise resolved
- });
- }
- }
- };
- // test.js
- const myCo = require('./my-co');
- const fs = require('fs');
- let gen = function * () {
- let data1 = yield pro1();
- console.log('data1: ' + data1);
- let data2 = yield pro2();
- console.log('data2: ' + data2);
- let data3 = yield pro3();
- console.log('data3: ' + data3);
- let data4 = yield pro4(data1 + '\n' + data2 + '\n' + data3);
- console.log('data4: ' + data4);
- return 'All done.'
- };
- // 调用myCo
- myCo(gen);
- // 延迟两秒resolve
- function pro1() {
- return new Promise((resolve, reject) = >{
- setTimeout(resolve, 2000, 'promise1 resolved');
- });
- }
- // 延迟一秒resolve
- function pro2() {
- return new Promise((resolve, reject) = >{
- setTimeout(resolve, 1000, 'promise2 resolved');
- });
- }
- // 写入Hello World到./1.txt文件中
- function pro3() {
- return new Promise((resolve, reject) = >{
- fs.appendFile('./1.txt', 'Hello World\n',
- function(err) {
- resolve('write-1 success');
- });
- });
- }
- // 写入content到./1.txt文件中
- function pro4(content) {
- return new Promise((resolve, reject) = >{
- fs.appendFile('./1.txt', content,
- function(err) {
- resolve('write-2 success');
- });
- });
- }
- // output
- data1: promise1 resolved
- data2: promise2 resolved
- data3: write-1 success
- data4: write-2 success
- Hello World
- promise1 resolved
- promise2 resolved
- write-1 success
来源: http://www.cnblogs.com/maskown/p/7763921.html