为什么.then(console.log)能够工作,而普通的console.log()会报错?

3
请参考附加的图片attached
这是我的第一个Node应用程序/脚本,我试图理解为什么在结尾处附加.then(console.log)时与仅使用console.log(list)时会得到不同的结果。

https://imgur.com/a/1kJ7gXX

如果图片无法加载,请查看代码片段。
// Generate list
const list = r.getSubreddit('AskReddit')
    .getTop({ time: 'all', limit: 1 })
    .map(post => ({
        title: post.title,
        url: post.url,
        upvotes: post.ups
    }))
    .then(console.log);

// console.log(list);

我收到了这个错误信息:
internal/util/inspect.js:373
  const symbols = Object.getOwnPropertySymbols(value);
                         ^

TypeError: 'ownKeys' on proxy: trap result did not include 'prototype'
    at Function.getOwnPropertySymbols (<anonymous>)
    at getKeys (internal/util/inspect.js:373:26)
    at formatRaw (internal/util/inspect.js:617:12)
    at formatValue (internal/util/inspect.js:540:10)
    at inspect (internal/util/inspect.js:197:10)
    at Object.formatWithOptions (util.js:84:12)
    at Console.(anonymous function) (internal/console/constructor.js:274:15)
    at Console.log (internal/console/constructor.js:284:61)
    at Object.<anonymous> (/Users/ik/Documents/Personal/list.js:27:9)
    at Module._compile (internal/modules/cjs/loader.js:799:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:810:10)
    at Module.load (internal/modules/cjs/loader.js:666:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
    at Function.Module._load (internal/modules/cjs/loader.js:598:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:862:12)
    at internal/main/run_main_module.js:21:11

list 不是一个数组,而是一个 Promise。至于错误,我猜它与 bluebird Promise 的实现方式有关,这使得它们在控制台中原始记录变得棘手。 - Patrick Roberts
实际上,snoowrap 本身使用 Proxy 来进行方法链接语法,并且它们的实现不支持对象的一般检查。只需按照他们的文档适当地使用 API 即可。 - Patrick Roberts
2个回答

0

第一个调用'r.getSubreddit(...).getTop(...).map(..)'返回一个Promise。这就是为什么你可以调用'.then(console.log)'

'.then'表示“一旦Promise被实现,或者换句话说,当从getSubreddit调用完成时,执行此操作。

当你说'console.log(list)'时,你正在请求一个可能存在也可能不存在的值。你创建了Promise,JavaScript立即调用下一个调用,即你的console.log,而list仍在等待Promise解决。当你使用.then()时,你是在说“在控制台记录输出之前,请等待此Promise解决。”


当你写 console.log(list) 时,实际上你正在记录一个对象(即 Promise),该对象封装了可能存在或不存在的值。但在那个时候,它肯定不存在。但这并没有解释为什么会抛出错误。 - Patrick Roberts
1
谢谢您的简单解释!我现在明白这两者之间的区别了。 - ik3o
不要忘记将答案加一或勾选你认为是正确答案,以便作者获得积分。我很高兴你能理解 JavaScript 的异步特性。等到你了解 async/await 之后,你会发现它们比 Promises 更容易上手。 - westandy

0

看起来你正在使用 snoowrap,根据 源代码(请参阅 snoowrap.js),getTop() 返回一个 Promise,这意味着你必须将你的 then 语句附加到它上面。如果 getTop() 返回一个数组,你可以像你所做的那样附加 map 语句,但它不是,它返回一个 Promise。

试试这个:

const list = r.getSubreddit('AskReddit')
    .getTop({ time: 'all', limit: 1 })
    .then(console.log);

或者使用地图:

const list = r.getSubreddit('AskReddit')
    .getTop({ time: 'all', limit: 1 })
    .then((topPosts) => {
        return topPosts.map(post => ({
            title: post.title,
            url: post.url,
            upvotes: post.ups
        })
    })
    .then(console.log);

无论如何,顺便提一下,请注意前面评论者关于您的第二个console.log所说的内容。由于您正在使用Promises,获取Subreddit的操作是异步的,这就是为什么您必须将所有命令链接在一起,每个步骤都要在前一个完成后执行。因此,要记录实际结果,它必须在then语句中。

我建议您对Promises进行一些功课:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises


编辑:

由于snoowrap在Promises下使用Bluebird,我可能是错误的,实际上您可以像以前一样使用map,因为{{link1:Bluebird包括此功能。}} 有趣的是,该库使用的Promises是通常Promise对象的包装器。也许他们正在不正确地实现该包装器,将其用作代理而没有正确设计,类似于此问题中的问题:

TypeError:'ownKeys' on proxy:trap result did not include 'arguments'


谢谢。我会查阅 Promise。 - ik3o

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接