Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为什么Node.js在这两种用法中传递参数的方式不同?

为什么Node.js在这两种用法中传递参数的方式不同?
EN

Stack Overflow用户
提问于 2015-12-26 18:47:00
回答 2查看 47关注 0票数 1

查看这个超级简单的node.js程序:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var g = { a : 1, b : 2 }

function callBack (key, value) {
    console.log("Callback called with key: " + key + "\nAnd value: " + value) ;
}

function doNothing (key, value, cb) {
    true ;
    console.log(key + ": doing nothing") ;
    cb() ;
}

function doLoop () {
    for (k in g) {
        f = function () {
            callBack(k, g[k]) ;
        }
        doNothing(k, g[k], f) ;
    }
}

doLoop() ;

运行时,它将生成以下输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a: doing nothing
Callback called with key: a
And value: 1
b: doing nothing
Callback called with key: b
And value: 2

好的。这是有意义的--每次调用回调时,它都有正确的参数。

现在看看这个程序:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var mysql = require('mysql') ;
var dbClient = undefined ;
var db_uri = "mysql://xxx:xxx@127.0.0.1/xxx" ;

var schema = {
    redirects : "(id int AUTO_INCREMENT, key VARCHAR(50), url VARCHAR(2048))",
    clicks : "(ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, IP VARBINARY(16))"
} ;

function createOnEmpty(err, results, fields, tableName, create_def) {
    console.log("createOnEmpty called on " + tableName) ;
    if (err) {
        console.error(err) ;
        process.exit(1) ;
    } else {
        if (0 == results.length) {
            dbClient.query(["create table ", tableName, create_def].join(" "),
                           function (err, results, fields) {} ) ;
        } else {
            console.log(tableName + " table already exists.") ;
        }
    }
    console.log("\n\n") ;
}

function setupSchema() {
    for (table in schema) {
        console.log("Checking for table: " + table) ;
        // FIXME: Why does this always seem to pass clicks as tablename?!
        dbClient.query(
           "show tables LIKE '" + table + "'",
           function (err, results, fields) {
               createOnEmpty(err, results, fields, table, schema[table])
           }
        );
    }
}

function handleDBConnect(err) {
    if (err) {
        console.error("ERROR: problem connecting to DB: " + err.code) ;
        process.exit(1) ;
    } else {
        console.log("Connected to database.") ;
        // Automatically set up the schema, if the tables don't exist
        setupSchema() ;
    }
}

function MySQLConnect() {
    dbClient = mysql.createConnection(db_uri) ;
    dbClient.connect(handleDBConnect) ;
}

MySQLConnect() ;

它的产出如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Connected to database.
Checking for table: redirects
Checking for table: clicks
createOnEmpty called on clicks



createOnEmpty called on clicks

尽管变量显然已被切换为“重定向”,但循环似乎两次都将参数“单击”作为参数“表”。

我想我对JavaScript/Node在这里的工作方式肯定有一些根本的误解。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-26 19:23:22

要理解这种行为,您需要了解以下两个核心js概念:

  • 闭包
  • 事件环

假设我们有全局变量a,输出a到控制台的log函数,调用log两次的主函数,第一次使用超时(异步),第二次只是简单的函数调用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var a = 42;

function log() {
    console.log(`a is ${a}`);
}

function main() {
    setTimeout(log, 100);
    a = 13;
    log();
}

main();

此代码产生以下输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a is 13
a is 13

为什么第一次a是13岁?

当您调用setTimeout时,它不会阻塞主js线程100 js,它只是在回调队列中添加日志函数。下一行是a = 13。由于a在函数体中没有使用var关键字声明,因此13被分配给在第一行代码中声明的a。然后,作为最后一行main函数的结果,我们得到了第一行输出。现在我们有了空的调用堆栈,代码中没有发生任何其他事情,但是回调队列中仍然有日志函数。在传递100 is之后,当且仅当调用堆栈为空(这就是我们的情况),则可以第二次调用log函数。它再次记录'a is 13',因为a-s值已经重新分配了。

这是对异步回调如何在javascript中工作的简短解释,这也是createOnEmpty called on clicks两次的原因。dbClient.query是异步的,当它第一次被调用时,您的for循环完成了它的执行,而table值是clicks。快速和肮脏的解决你的问题将是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for (table in schema) {
    console.log("Checking for table: " + table) ;
    (function (table) {
        dbClient.query("show tables LIKE '" + table + "'",
                   function (err, results, fields) {
                       createOnEmpty(err, results, fields, table,
                                     schema[table]) } );
    )(table);
}

这个立即调用的函数在范围内的每个循环迭代中都会存储table值。

票数 2
EN

Stack Overflow用户

发布于 2015-12-26 19:16:31

当调用dbClient.query的回调时,循环已经完成,将您的(隐式全局) table变量留在schema的最后一个键上。

您需要使用使用匿名函数对其进行范围调整。(参见这里的各种答案),或者使用基于回调的迭代,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function setupSchema() {
    Object.keys(schema).forEach(function (table) {
        console.log("Checking for table: " + table) ;
        // FIXME: Why does this always seem to pass clicks as tablename?!
        dbClient.query(
           "show tables LIKE '" + table + "'",
           function (err, results, fields) {
               createOnEmpty(err, results, fields, table, schema[table])
           }
        );
    });
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34477157

复制
相关文章
select2的使用
你必须在其它地方能获取到这个select标签,所以要为其设置id、class或者是name以便能得到这个标签。multiple属性是是否可以多选。option是下拉框中多选的内容。例如在angluar中,使用ng-repeat循环出来值xxx,然后放在option中供select使用。
晓果冻
2022/06/17
1.5K0
ui-select官方教程(二)——ui-select指令
ui-select指令 ui-select的指令和事件 属性 选项 描述 值 默认值 multiple 多选,直接加上multiple属性 close-on-select 在多选情况下,选中一项,就关闭下拉项 boolean true append-to-body 在多选情况下,选中项追加显示 boolean false ng-disabled 控件被禁用 boolean true ng-model 控件绑定对象 String,number,array undefined search-enabled
逝兮诚
2019/10/30
2.7K0
select2的搜索框不能输入搜索内容
按照select2官网配置完后,搜索框弹出后无法输入内容,究竟怎么回事,于是在其他页面尝试了select2,发现可以啊,为什么在这个地方不可以,终于找到了造成这个问题的不同之处:select2在模态对话框中会失效。找到了问题所在,但不知道如何解决:百度或者google,最终找到了解决方案:
johnhuster的分享
2022/03/29
1.4K0
在 Discourse 中如何使用输入对话框
如下图显示的内容,可以在输入框中输入文本,然后在主题中可以根据你输入的文本重新生成字符串:
HoneyMoose
2021/09/08
2.2K0
在 Discourse 中如何使用输入对话框
在Ubuntu 20.04中禁用motd欢迎消息
本篇文章重点讲解一下在Ubuntu 20.04中禁用motd欢迎消息具体方法,有需要的小伙伴可以参考一下。
会长君
2023/04/25
2.6K0
禁止在input中输入中文
提示:设置ime-mode为disabled的意思是禁止在输入时禁止用户激活输入中文,韩文,日文等的输入法(IME)状态,因为这个只能检测到键盘的输入,对通过鼠标操作的粘贴和拖放无效。
崔笑颜
2020/06/08
4K0
win禁用shift切换输入法
在很多场景下,我们都会使用到shift来完成一些功能,最常见的就是输出键盘上面一排标点符号,但是往往在使用shift时会出现切换输入法的情况,在一些仅英文或者中文输入的场合切换会对工作效率造成影响,这里介绍禁用shift切换输入法的方法,仅仅采用ctrl+空格的方式完成切换输入法。
timerring
2022/09/21
6K0
win禁用shift切换输入法
select2无法输入搜索和宽度问题解决
这时候select2的搜索框无法输入,一般有两方面的原因 1.检查下modal的div中是否有tabindex=”-1”,这个属性
botkenni
2019/09/02
1.7K0
select2无法输入搜索和宽度问题解决
yii2使用select2
Text-to-speech function is limited to 200 characters
botkenni
2019/09/02
8990
yii2使用select2
select2 使用教程(简)「建议收藏」
用了这么久的Select2插件,也该写篇文章总结总结。当初感觉Select2不是特别好用,但又找不到比它更好的下拉框插件。
全栈程序员站长
2022/09/12
25.1K0
select2 使用教程(简)「建议收藏」
在python中实现密文输入
本文由腾讯云+社区自动同步,原文地址 http://blogtest.stackoverflow.club/input-password-in-python/
羽翰尘
2019/11/21
1.8K0
【DB笔试面试727】在Oracle中,如何禁用HAIP?
说明,ora.cluster_interconnect.haip的ENABLED属性的原始值为1:
AiDBA宝典
2020/01/20
1.8K0
如何使用 Selenium 在 HTML 文本输入中模拟按 Enter 键?
Selenium是 Python 中可用的内置模块,允许用户制作自动化套件和测试。我们可以使用 selenium 构建代码或脚本以在 Web 浏览器中自动执行任务。Selenium 用于通过自动化测试软件。此外,程序员可以使用 selenium 为软件或应用程序创建自动化测试用例。
海拥
2021/12/20
8.4K0
在 Vue 中创建自定义输入
基于组件的库或框架(如 Vue )可以创建 可重用组件 ,它能在各自应用程序中相互传递数据,这些框架能确保这些数据是一致的,并且(希望)简化了它们的使用方式。
疯狂的技术宅
2019/03/28
6.5K0
Python 教程之输入输出(1)—— 在 Python 中接受输入
开发人员经常需要与用户交互,以获取数据或提供某种结果。今天的大多数程序都使用对话框来要求用户提供某种类型的输入。而 Python 为我们提供了两个内置函数来读取键盘输入。
海拥
2022/09/16
1.7K0
Python 教程之输入输出(1)—— 在 Python 中接受输入
在评论输入框中插入表情
最近在做一个后台管理系统,要求可以对前台用户的作品进行评论,而评论要可以输入表情,常规的文字输入框都是用的文本域textarea来做的,但这种输入框只能输入文字,没有办法输入表情图标,这个时候可编辑div就能起到作用了,那么如何在可编辑的div中插入表情呢?
越陌度阡
2020/11/26
4.1K0
初次使用AngularJS中的ng-view,路由控制
AngularJS中的route可以控制页面元素的改变,使多页面变成一个单页面 第一步:引入必要的js: <script src="js/lib/angular.js"></script> <script src="js/lib/angular-animate.min.js"></script> <script src="js/lib/angular-route.min.js"></script> <script src="app.js"></script> 第二步:准备好一个单页: <body ng-a
Ryan-Miao
2018/03/13
1.6K0
在文件中输入字符串HelloWord
Our life today is three years ago, our life three years later is today's choice.
小Bob来啦
2020/12/15
2.5K0
在文件中输入字符串HelloWord
点击加载更多

相似问题

使用Select2禁用用于自动完成的输入

12

在更新来自ng重复的ng禁用输入时停止ng模型

20

ng-禁用所有输入元素

10

Select2 -禁用用户输入选择

23

在ng-repeat下的tfoot中禁用输入控件

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文