我遇到了以下代码的回调函数。我了解代码,但无法解决。似乎太违反直觉了。
function greet(name,callback1){
callback1(name)
}
greet("John Cena", function (somerandomName) {
console.log(somerandomName);
return someRandomName;
}); // Output is John Cena and undefined.
这是我从代码中所了解的:
我们定义一个函数greet
,该函数带有2个参数name
和callback1
。然后我们说callback1的参数是name。我们没有在greet
函数中返回任何内容,为什么?
当我们调用greet
函数时,我们将第二个参数作为匿名函数传递,其参数为someRandomName
。然后我们console.log(someRandomName)
。
我添加了返回someRandomName,但是此返回不起作用,我得到了打印的语句,后跟 undefined
有人可以用简单的话解释一下吗,这似乎太违反直觉了。
答案 0 :(得分:2)
因此,我认为了解函数本身可以作为参数很重要。
在此示例中,您传递了一个字符串作为第一个参数,然后传递了一个以该字符串作为参数作为第二个参数的函数。
函数并不总是需要返回某些东西。函数通常可能会对dom执行操作,获取数据,配置某些内容或更改现有变量。当然,如果需要的话,您可以退货。
像您一样增加回报并没有多大作用。为了实际返回名称值,您必须编写这样的原始函数。
function greet(name,callback1){
return callback1(name)
}
那么你可以做这样的事情
var wrestler = greet("John Cena", function (somerandomName) {
console.log(somerandomName);
return somerandomName;
});
console.log(wrestler) // prints John Cena
这有点奇怪,因为它没有实际用途。这样的事情可能会帮助您了解发生了什么。
function greet(name, callback) {
callback(name)
}
greet('John Cena', function(name){
console.log('Hello ' + name) // prints Hello John Cena
})
OR return something and use it to manipulate dom
function greet(name, callback) {
return callback(name)
}
var greeting = greet('John Cena', function(name){
return 'Hello ' + name
})
document.getElementById('message').innerHTML = greeting
// somewhere in HTML...
<h1 id='message'></h1>
无论哪种方式,至少我们现在都在对第一个参数做一些事情。回调可以做的事情是无限的。
回调是javascript的基本功能。当函数的第一部分是异步的(例如对api或数据库的调用)时,它们会发挥作用。在这种情况下,第一部分将是对数据库的调用,并且在从初始调用中获取值之前不会触发回调。最近,由于Promises,这种回调模式的使用量有所减少,但回调仍然有用。
因此是一个从前端到后端的通用api调用示例。通常,这可以使用Fetch Api或通过Request或Axios之类的库来完成。请记住,调用端点的第一个函数需要花费一些时间来执行和获取数据。在返回该数据之前,不会触发回调。当然,后端会有一个将错误或数据发送回回调的函数。我不想让事情变得过于复杂,而只是想知道回调通常用于什么。
function getDataFromBackend(endPoint, callback) {
callback(error, data)
}
getDataFromBackend('/api/user', function(error, data) {
if (error) {
// handle error - show user error message in ui, etc
}
// do something with data - such as display welcome message to user, etc
})
我建议使用回调进行练习。我发现当我使用Node或使用前端和后端构建应用程序时,我会实现很多回调,因为发生了很多异步通信。希望我回答了你的问题。
答案 1 :(得分:1)
首先,您拥有return someRandomName
,但您的参数称为somerandomName
。变量区分大小写;这就是为什么您的返回值与您想要的不同。
您的问题是,为什么我们不返回greet
函数中的任何内容。答案是“我不知道”。您 可以 返回某些内容。一些函数返回东西;有些功能没有。这与这里的回调安排无关。
function greet(name,callback1){
return callback1(name)
}
var finalResult = greet("John Cena", function (someRandomName) {
console.log(someRandomName);
return someRandomName;
});
现在finalResult
将是"John Cena"
。
如果在使用匿名函数的任何地方都提供帮助,则可以轻松使用命名函数。 (在实践中通常比较丑陋,但是为了理解这些概念...)
function greet(name,callback1){
return callback1(name)
}
function myGreeterFunction(someRandomName) {
console.log(someRandomName);
return someRandomName;
});
var finalResult = greet("John Cena", myGreeterFunction);
在这种情况下,现在更容易看出callback1(name)
与说myGreeterFunction(name)
是同一件事。
答案 2 :(得分:1)
这是JavaScript的一种过时的方法,您完全正确,因为它反直观。在这个特定的示例中,使用callback
编写代码没有任何优势,可能应该作为一个承诺来编写
greet("John Cena")
.then(() => {
return 'Next Action'
})
.then(nextAction => {
console.log(nextAction)
})
正如@ mark-meyer所指出的,如果您有一个异步事件,则需要这种方法。
实际上, AWS Lamda 函数实际上有一个可选 callback
定义为它的第三个参数。 exports.myHandler = function(event, context, callback) {}
。坦率地说,我认为这只能涵盖不许基于第三方库的情况。
尽管将callback
传递给函数可能永远都不是正确的方法,但在某些情况下,将function
传递给function
是有价值的。也许在 pub / sub 系统中。
const events = {}
function subscribe (event, func) {
if (events[event]) {
events[event].push(func)
} else {
events[event] = [func]
}
}
function publish (event) {
if (events[events]) {
events[event].forEach(func => func())
}
}
如果您使用fp中的RamdaJs方法链接进行编写,链接功能将是编写内容的重要组成部分。
@ pi2018清除了一些内容吗?
答案 3 :(得分:0)
一般技术称为continuation-passing style –与direct style形成对比。
该技术确实允许出现一些有趣的程序。下面,我们有两个普通函数add
和mult
。我们使用cont
编写了两个程序,这使我们可以将这些函数串在一起,其中每一步都是
之前一个的延续。
const cont = x => k =>
cont (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
cont (1) (add (2)) (mult (3)) (console.log) // 9
// 1 ->
// x => 2 + x
// cont (3) ->
// x => 3 * x
// cont (9) ->
// x => console.log (x)
// cont (undefined)
我们可以根据需要对任意数量的操作进行排序–
const cont = x => k =>
cont (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
cont (2) (mult (2)) (mult (2)) (mult (2)) (mult (2)) (console.log) // 32
// 2 ->
// x => 2 * x
// cont (4) ->
// x => 2 * x
// cont (8) ->
// x => 2 * x
// cont (16) ->
// x => 2 * x
// cont (32) ->
// x => console.log (x)
// cont (undefined)
可以使用连续传递样式来实现并发程序,但是JavaScript现在提供了更好的本机并发原语Promise。甚至还提供了新的async
和await
语法,使Promises的使用更加容易。
正如Wikipedia所指出的那样,连续传递样式在编译器中使用较多,在程序员中则较少。如果您尝试编写并发程序,我强烈建议您改用Promises。更高版本的Node包括util.promisify,它允许用户将继续传递样式功能转换为Promise-returning异步功能。