diff --git a/lib/db.js b/lib/db.js index a1fe32c..8ad7277 100644 --- a/lib/db.js +++ b/lib/db.js @@ -1,13 +1,51 @@ -const Tapable = require('tapable') +const { + SyncWaterfallHook, + AsyncSeriesWaterfallHook +} = require('tapable') -class DB extends Tapable { - constructor() { +class DB { + constructor(options) { // TODO + this.options = options ? options : {} + + this.hooks = { + endpoint: new AsyncSeriesWaterfallHook(['options']), + options: new SyncWaterfallHook(['options']), + judge: new SyncWaterfallHook(['res']) // 使用SyncWaterfallHook才会有返回值 + } + } + + modifyOptions(options) { + this.hooks.options.call(options) + + Object.keys(options).forEach(key => { + if (options.hasOwnProperty(key)) { + this.options[key] = options[key] + } + }) } - request() { + request(options) { + if (options) { + this.modifyOptions(options) + } + // TODO + return this.hooks.endpoint + .promise(this.options) + .then(res => { + const judge = this.hooks.judge.call(res) + + if (!judge) { + throw res + } + + return res + }) + .catch(err => { + return Promise.reject(err) + }) } } -module.exports = DB \ No newline at end of file +module.exports = DB diff --git a/package.json b/package.json index aad5780..1ec241c 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "webpack": "^3.5.3" }, "dependencies": { + "tapable": "^2.2.1", "puppeteer": "^16.2.0" } } diff --git a/test/test.js b/test/test.js index f8fecbb..1752ec8 100644 --- a/test/test.js +++ b/test/test.js @@ -17,8 +17,8 @@ describe('DB', function () { constructor(options) { super(options) - this.plugin('endpoint', function () { - return new Promise((resolve) => { + this.hooks.endpoint.tapPromise('endpoint', function () { + return new Promise(resolve => { setTimeout(() => { resolve({ retcode: 0, res: { msg: 'hello world' } }) }, 0) @@ -27,47 +27,70 @@ describe('DB', function () { } } - const xx = new XX() - xx.request() - .then((res) => { - assert.equal(res.res.msg, 'hello world') - done() - }) + const xx = new XX({}) + xx.request().then(res => { + assert.equal(res.res.msg, 'hello world') + done() + }) }) it('可以根据不同的options,使用不同的endpoint', function (done) { class AA extends DB { constructor(options) { super(options) - this.plugin('endpoint', function (options) { + + /* + 梳理一下流程: + 1. 第一次请求时,type为1,会先执行endpoint1,将{ retcode: 1, msg: 'logout' }传递给endpoint2 + 2. endpoint2接收到{ retcode: 1, msg: 'logout' }后,走else逻辑,将其传递给第一次请求的then回调 + 3. 发出第二次请求,type为0,先执行endpoint1,走else逻辑,将{ type: 0 }传递给endpoint2 + 4. endpoint2接收到{ type: 0 },会将{ retcode: 0, res: { msg: 'hello world' } }传递给第二个then回调 + */ + + this.hooks.endpoint.tapPromise('endpoint1', function (options) { if (options.type === 1) { - return new Promise((resolve) => { + return new Promise(resolve => { setTimeout(() => { resolve({ retcode: 1, msg: 'logout' }) }, 0) }) + } else { + // AsyncSeriesWaterfallHook需要将返回值传递给下一个函数 + return new Promise(resolve => { + setTimeout(() => { + resolve(options) + }, 0) + }) } }) - this.plugin('endpoint', function (options) { + + this.hooks.endpoint.tapPromise('endpoint2', function (options) { if (options.type === 0) { - return new Promise((resolve) => { + return new Promise(resolve => { setTimeout(() => { resolve({ retcode: 0, res: { msg: 'hello world' } }) }, 0) }) + } else { + return new Promise(resolve => { + setTimeout(() => { + resolve(options) + }, 0) + }) } }) } } - const aa = new AA + const aa = new AA() // 如果 options.type === 1,则返回第一个答案 aa.request({ type: 1 }) .then(res => { assert.equal(res.retcode, 1) // 如果 options.type === 0,则返回第二个答案 return aa.request({ type: 0 }) - }).then(res => { + }) + .then(res => { assert.equal(res.retcode, 0) done() }) @@ -77,12 +100,12 @@ describe('DB', function () { class YY extends DB { constructor(options) { super(options) - this.plugin('options', (options) => { + this.hooks.options.tap('options', options => { // modify options options.flag = true return options }) - this.plugin('endpoint', (options) => { + this.hooks.endpoint.tapPromise('endpoint', options => { // init assert.equal(options.init, true) // merge @@ -100,31 +123,30 @@ describe('DB', function () { } const yy = new YY({ init: true }) - yy.request({ url: 'my://hello' }) - .then((res) => { - done() - }) + yy.request({ url: 'my://hello' }).then(res => { + done() + }) }) it('可以设置多个options插件', function (done) { class BB extends DB { constructor(options) { super(options) - this.plugin('options', (options) => { + this.hooks.options.tap('options', options => { // modify options options.flag = true return options }) - this.plugin('options', (options) => { + this.hooks.options.tap('options', options => { // modify options,后面的覆盖前面的 options.flag = false - return options + return options }) - this.plugin('options', (options) => { + this.hooks.options.tap('options', options => { options.url = 'you://hello' return options }) - this.plugin('endpoint', (options) => { + this.hooks.endpoint.tapPromise('endpoint', options => { // init assert.equal(options.init, true) // merge @@ -142,60 +164,82 @@ describe('DB', function () { } const bb = new BB({ init: true }) - bb.request({ url: 'my://hello' }) - .then((res) => { - done() - }) + bb.request({ url: 'my://hello' }).then(res => { + done() + }) }) it('可以通过judge插件判断返回是否正确', function (done) { class CC extends DB { constructor(options) { super(options) - this.plugin('endpoint', function (options) { + + this.hooks.endpoint.tapPromise('endpoint', function (options) { if (options.type === 1) { - return new Promise((resolve) => { + return new Promise(resolve => { setTimeout(() => { resolve({ retcode: 1, msg: 'logout' }) }, 0) }) + } else { + return new Promise(resolve => { + setTimeout(() => { + resolve(options) + }, 0) + }) } }) - this.plugin('endpoint', function (options) { + + this.hooks.endpoint.tapPromise('endpoint', function (options) { if (options.type === 0) { - return new Promise((resolve) => { + return new Promise(resolve => { setTimeout(() => { resolve({ retcode: 0, res: { msg: 'hello world' } }) }, 0) }) + } else { + return new Promise(resolve => { + setTimeout(() => { + resolve(options) + }, 0) + }) } }) - this.plugin('judge', function (res) { - if (res.retcode !== 0) return true + this.hooks.judge.tap('judge', function (res) { + // retcode为0表示请求成功 + // 如果没有注册judge hook,会将res直接返回 + return res.retcode === 0 }) } } - const cc = new CC + const cc = new CC() cc.request({ type: 0 }) - .then((res) => { + .then(res => { assert.equal(res.res.msg, 'hello world') return cc.request({ type: 1 }) - }).then((res) => { - done(new Error('不应该进入正确回调,应当进入失败回调,因为retcode为1')) - }, (res) => { - assert.equal(res.retcode, 1) - assert.equal(res.msg, 'logout') - done() }) + .then( + res => { + done( + new Error('不应该进入正确回调,应当进入失败回调,因为retcode为1') + ) + }, + res => { + assert.equal(res.retcode, 1) + assert.equal(res.msg, 'logout') + done() + } + ) }) it('可以reject数据', function (done) { class ZZ extends DB { constructor(options) { super(options) - this.plugin('endpoint', function () { + + this.hooks.endpoint.tapPromise('endpoint', function () { return new Promise((resolve, reject) => { reject() }) @@ -203,13 +247,15 @@ describe('DB', function () { } } - const zz = new ZZ + const zz = new ZZ() - zz.request() - .then(() => { + zz.request().then( + () => { done(new Error('should not trigger resolve callback')) - }, () => { + }, + () => { done() - }) + } + ) }) -}) \ No newline at end of file +})