[英]Add an extra parameter to a callback function in Javascript
Hello Stackoverflow users,您好 Stackoverflow 用户,
Many peoples like me searched for how to pass extra arguments to a callback function.许多像我这样的人都在搜索如何将额外的参数传递给回调函数。 The questions have similar titles but actually they have different challenges and many ways to solve.这些问题的标题相似,但实际上它们具有不同的挑战和许多解决方法。 Plus, it is always a pleasure to share practices to be more experienced.另外,分享实践以增加经验总是很高兴。
Recently, I faced a pretty simple challenge in my node js project.最近,我在我的 node js 项目中遇到了一个非常简单的挑战。 One of the APIs I communicate with has an SDK that works synchronically.我与之通信的其中一个 API 有一个同步工作的 SDK。 And I used to pass callback functions every time (which is annoying when you have requests depending on each other and some data needs to transfer within the app layers).而且我曾经每次都传递回调函数(当您有相互依赖的请求并且需要在应用程序层内传输一些数据时,这很烦人)。
Imagine a plan payment flow that goes like this, a client sends a request to the server including the selected plan and his ID.想象一下这样的计划支付流程,客户端向服务器发送一个请求,其中包括所选计划和他的 ID。 When the server API layer receives the request data, it passes it to a third-party service function ( .create(...)
).服务器 API 层收到请求数据后,会将其传递给第三方服务函数( .create(...)
)。 The third-party service function receives a callback with 2 parameters function(err, plan_document)
.第三方服务函数接收带有 2 个参数function(err, plan_document)
的回调。 And then, the callback is supposed to apply the selected plan logic on the client by the ID in the request.然后,回调应该通过请求中的 ID 将选定的计划逻辑应用于客户端。
** We need to pass the client's and the plan's data to the callback function to apply the logic. ** 我们需要将客户端和计划的数据传递给回调函数以应用逻辑。 The third-party service provides to the callback a plan_document parameter and we still need to somehow pass the client id from the API layer to the service.第三方服务为回调提供了一个 plan_document 参数,我们仍然需要以某种方式将客户端 ID 从 API 层传递给服务。
The code will look like this.代码将如下所示。
const create_plan_agreement = (req, res) => {
// some code
var client_id = req.auth.client_id;
third_party.plan_agreement.create({}, update_plan_agreement);
};
const update_plan_agreement = (err, plan_document, client_id) => {
/*
The third-party `third_party.plan_agreement.create` function passes the first
two parameters and somehow we need to add the client_id
*/
console.log('client plan activated');
active_client_plan(plan_document, client_id);
};
------------------ EDIT ------------------ - - - - - - - - - 编辑 - - - - - - - - -
I wonder what if the flow was longer and I need the client id farther than the update function like this.我想知道如果流程更长并且我需要客户端 ID 比这样的更新功能更远怎么办。
const create_plan_agreement = (req, res) => {
// some code
var client_id = req.auth.client_id;
third_party.plan_agreement.create({}, update_plan_agreement);
};
const update_plan_agreement = (err, plan_document) => {
console.log('plan activated, send notification to the client');
third_party.plan_agreement.update(plan_document, send_agreement_notification);
};
const send_agreement_notification = (err, plan_document) => {
console.log('client plan activated');
active_client_plan(plan_document, this.client_id);
};
What should I do in this case?在这种情况下我该怎么办? Should I keep repeating the .bind({'client_id': client_id})
function until the last step in the flow?我是否应该一直重复.bind({'client_id': client_id})
函数,直到流程的最后一步?
If you want to support older people, you can easily bind using a containing callback, like this:如果您想支持老年人,您可以使用包含回调轻松绑定,如下所示:
const create_plan_agreement = (req, res) => { // some code var client_id = req.auth.client_id; third_party.plan_agreement.create({}, function(params, from, create) { update_plan_agreement(params, from, create, client_id) }); }; const update_plan_agreement = (err, plan_document, client_id) => { /* The third-party `third_party.plan_agreement.create` function passes the first two parameters and somehow we need to add the client_id */ console.log('client plan activated'); active_client_plan(plan_document, client_id); };
The traditional way is to use a closure.传统的方法是使用闭包。 Define the functions inside the parent's scope so that they can access the client_id
as an enclosed variable (kind of like global variables):在父范围内定义函数,以便它们可以将client_id
作为封闭变量(有点像全局变量)访问:
const create_plan_agreement = (req, res) => {
// some code
var client_id = req.auth.client_id;
const update_plan_agreement = (err, plan_document) => {
console.log('plan activated, send notification to the client');
third_party.plan_agreement.update(plan_document, send_agreement_notification);
};
const send_agreement_notification = (err, plan_document) => {
console.log('client plan activated');
// Note: this function can access client_id
// because it is in scope
active_client_plan(plan_document, client_id);
};
third_party.plan_agreement.create({}, update_plan_agreement);
};
Closures are to scopes what objects are to classes.闭包之于作用域就像对象之于类。 A closure is an instance of a scope.闭包是作用域的一个实例。 So unlike regular global variable, each call to create_plan_agreement()
will create its own closure with its own copy of client_id
.因此,与常规全局变量不同,每次调用create_plan_agreement()
都会使用自己的client_id
副本创建自己的闭包。
With modern javascript it is often easier to handle this with Promise
s.使用现代 javascript,通常使用Promise
更容易处理这个问题。 Convert legacy functions to return a Promise
and then you can use async/await
:转换遗留函数以返回Promise
,然后您可以使用async/await
:
const create_plan_agreement = async (req, res) => {
// some code
var client_id = req.auth.client_id;
try {
var plan_document = await plan_agreement_create({});
var updated_plan_document = await update_plan_agreement(plan_document);
send_agreement_notification(updated_plan_document, client_id);
}
catch (err) {
// handle errors here.
}
};
const plan_agreement_create = (arg) {
return new Promise ((ok, fail) => {
third_party.plan_agreement.create({}, (err, result) => {
if (err) {
return fail(err);
}
ok(result);
});
})
}
const update_plan_agreement = (plan_document) => {
return new Promise ((ok, fail) => {
third_party.plan_agreement.update(plan_document, (err, result) => {
if (err) return fail(err);
ok(result);
});
});
};
const send_agreement_notification = (plan_document, client_id) => {
active_client_plan(plan_document, client_id);
};
Or even without async/await
Promise
s still make callbacks easier to use:或者即使没有async/await
Promise
仍然使回调更易于使用:
const create_plan_agreement = async (req, res) => {
// some code
var client_id = req.auth.client_id;
plan_agreement_create({})
.then(doc => update_plan_agreement(doc));
.then(doc => {
send_agreement_notification(doc, client_id)
})
.catch(err => {
// handle errors here.
});
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.