让人头痛的Generator 函数的异步应用真的有用吗?( 六 )
上一节已经介绍了基于 Thunk 函数的自动执行器 。 下面来看 , 基于 Promise 对象的自动执行器 。 这是理解 co 模块必须的 。
基于 Promise 对象的自动执行还是沿用上面的例子 。 首先 , 把fs模块的readFile方法包装成一个 Promise 对象 。
var fs = require('fs');var readFile = function (fileName){return new Promise(function (resolve, reject){fs.readFile(fileName, function(error, data){if (error) return reject(error);resolve(data);});});};var gen = function* (){var f1 = yield readFile('/etc/fstab');var f2 = yield readFile('/etc/shells');console.log(f1.toString());console.log(f2.toString());};然后 , 手动执行上面的 Generator 函数 。
var g = gen();g.next().value.then(function(data){g.next(data).value.then(function(data){g.next(data);});});手动执行其实就是用then方法 , 层层添加回调函数 。 理解了这一点 , 就可以写出一个自动执行器 。
function run(gen){var g = gen();function next(data){var result = g.next(data);if (result.done) return result.value;result.value.then(function(data){next(data);});}next();}run(gen);上面代码中 , 只要 Generator 函数还没执行到最后一步 , next函数就调用自身 , 以此实现自动执行 。
co 模块的源码co 就是上面那个自动执行器的扩展 , 它的源码只有几十行 , 非常简单 。
首先 , co 函数接受 Generator 函数作为参数 , 返回一个 Promise 对象 。
function co(gen) {var ctx = this;return new Promise(function(resolve, reject) {});}在返回的 Promise 对象里面 , co 先检查参数gen是否为 Generator 函数 。 如果是 , 就执行该函数 , 得到一个内部指针对象;如果不是就返回 , 并将 Promise 对象的状态改为resolved 。
function co(gen) {var ctx = this;return new Promise(function(resolve, reject) {if (typeof gen === 'function') gen = gen.call(ctx);if (!gen || typeof gen.next !== 'function') return resolve(gen);});}接着 , co 将 Generator 函数的内部指针对象的next方法 , 包装成onFulfilled函数 。 这主要是为了能够捕捉抛出的错误 。
function co(gen) {var ctx = this;return new Promise(function(resolve, reject) {if (typeof gen === 'function') gen = gen.call(ctx);if (!gen || typeof gen.next !== 'function') return resolve(gen);onFulfilled();function onFulfilled(res) {var ret;try {ret = gen.next(res);} catch (e) {return reject(e);}next(ret);}});}最后 , 就是关键的next函数 , 它会反复调用自身 。
function next(ret) {if (ret.done) return resolve(ret.value);var value = http://kandian.youth.cn/index/toPromise.call(ctx, ret.value);if (valuereturn onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '+ 'but the following object was passed: "'+ String(ret.value)+ '"'));}上面代码中 , next函数的内部代码 , 一共只有四行命令 。
第一行 , 检查当前是否为 Generator 函数的最后一步 , 如果是就返回 。
第二行 , 确保每一步的返回值 , 是 Promise 对象 。
第三行 , 使用then方法 , 为返回值加上回调函数 , 然后通过onFulfilled函数再次调用next函数 。
第四行 , 在参数不符合要求的情况下(参数非 Thunk 函数和 Promise 对象) , 将 Promise 对象的状态改为rejected , 从而终止执行 。
推荐阅读
- 雷军发布会上的话!让人看到了雷军的“另一面”!网友:有良心
- 机器人送雪球!哈尔滨这场专业“打雪仗”,太让人羡慕了
- 2021年的中兴有多让人期待?倪飞在新年贺词中表了态
- XSX主机散热、噪声实机测试 出色表现让人满意
- 华为 WATCH FIT 体验:只有 34 克重,一款愿意让人戴着睡觉的智能手表
- 华为越南代言人走红,手机好不好用不清楚,让人挪不开眼睛
- 微信右上角+号隐藏5个黑科技功能,一键开启,让人相见恨晚
- 支付宝和微信支付,到底哪个使用人数更多呢?答案让人比较意外
- iPhone 11再度降价,直降700让人觉得有些太不保值
- iPhone12来了PVD工艺让人亮眼
