使用代理模拟异步构建器模式API

问题描述 投票:0回答:1

我正在尝试模拟 knex 进行测试。一切似乎都有效,但将代理附加到数组作为原型似乎消除了数组的可迭代性。

这是模拟函数。以下内容适用于对象。

const mock = (data) => {
    const orgData = structuredClone(data)

    Object.setPrototypeOf(
        data,
        new Proxy(
            {},
            {
                get(_, prop) {
                    if (prop === 'then') {
                        return orgData
                    }

                    if (typeof prop === 'symbol') {
                        return orgData
                    }

                    return () => mock(orgData)
                },
            }
        )
    )

    return data
}
const mm = mock([
    {
        name: 'user',
    },
])

const run = async () => {
    const res = await mm.select('*').where('name', 'user')
    const [first] = res
    //             ^^^^^
    // TypeError: res is not iterable
    //     at run (.../test.js:35:18)
}
run()

当链前存在

await
时,将调用代理
get
,并将
then
作为
prop
的值。这是最后一次通话。这会正确返回
[ { name: 'user' } ]
。然而,分配给
res
变量的值看起来像这样
{ '0': { name: 'user' } }
。我想知道是否可以将
prototype
分配给数组而不使其成为对象。

javascript proxy mocking prototype
1个回答
0
投票

我是发布这个问题的同一个人。解决方案是根本不设置原型,而是直接代理承诺本身。

const mock = (data) => {
      return new Proxy(Promise.resolve(data), {
            get(target, prop) {
                  if (prop in target) {
                        const promise = Promise.resolve(target)
                        // NOTE: when `then` is called independently, this will be global so it
                        // wouldn't be resolved correctly. So here binding the context to the
                        // function to make it work
                        return promise.then.bind(promise)
                  }

                  return () => mock(target)
            },
      })
}

const mm = mock([
      {
            name: 'user',
      },
])

const run = async () => {
      const res = await await mm.select('*').where('name', 'user')
      console.log(res)
      const [first] = res
      console.log(first)
}

run()

输出:

:!node test.js
[ { name: 'user' } ]
{ name: 'user' }
© www.soinside.com 2019 - 2024. All rights reserved.