javascript - Korrekt sätt att skicka och anropa en funktion
När jag använder ett externt SDK i Node märkte jag att jag skrev mycket upprepad kod. T.ex.:
async function one(): Promise<any> {
return new Promise((resolve, reject) => {
sdk.one(function(err, req, res) {
if (err) {
return reject(err);
}
resolve(res);
});
});
}
async function two(): Promise<any> {
return new Promise((resolve, reject) => {
sdk.two(function(err, req, res) {
if (err) {
console.log(err);
return reject(err);
}
resolve(res);
});
});
}
Jag ville förenkla och abstrahera det för att göra det renare och tänkte på detta:
async function runner(fn, params?): Promise<any> {
return new Promise(function(resolve, reject) {
const _CB = cb.bind({ resolve, reject });
if (params) {
return fn(params, _CB);
}
return fn(_CB);
});
}
const one = async (): Promise<any> => {
return runner(sdk.one);
};
const two = async (): Promise<any> => {
return runner(sdk.two);
};
Jag får ett fel när jag kör detta, alltså this.helper is not a function. Problemet, tror jag, är att Javascript passerar efter värde. Så när jag kör fn(_CB) inne i runner och det försöker referera till en funktion på dess förälder, this.helper, vet det inte vad this är eftersom fn bokstavligen bara är ett kopierat kodblock. Egentligen, innan jag tänkte på detta, försökte jag util.Promisify sdk-funktionerna, men jag får samma fel som jag får här.
Jag tänkte på denna lösning, men jag undrar om det finns ett bättre sätt?
async function runner(fn, params?): Promise<any> {
return new Promise(function(resolve, reject) {
const _CB = cb.bind({ resolve, reject });
if (params) {
return fn(params, _CB);
}
return fn(_CB);
});
}
const one = async (): Promise<any> => {
return runner((x) => sdk.one(x));
};
Svar #1
Förlorar du kontext när SDK:n försöker kalla tillbaka dig? Du kan använda pilfunktioner för att bevara kontexten i dessa anrop. Det fungerar på ett liknande sätt som din mellanliggande _CB-variabel för äldre mål, men i uppdaterade ECMAScript-versioner är det inbyggt.
async function one(): Promise<any> {
return new Promise((resolve, reject) => {
sdk.one((err, req, res) => { // Scope preserving arrow function
if (err) {
return reject(err);
}
resolve(res);
});
});
}
async function two(): Promise<any> {
return new Promise((resolve, reject) => {
sdk.two((err, req, res) => { // and here
if (err) {
console.log(err);
return reject(err);
}
resolve(res);
});
});
}
Svar #2
Tja, du är i JavaScript, språket som låter dig göra nästan vad som helst. Du kan anropa funktioner dynamiskt
async function promisify(fnName): Promise<any> {
return new Promise((resolve, reject) => {
sdk[fnName](function(err, req, res) {
if (err) {
return reject(err);
}
resolve(res);
});
});
}
och kalla det som promisify('one')
Om du använder den nuvarande LTS 8.X Node-versionen eller högre kan du använda https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original
Om inte, kan du försöka använda bluebird-metoden för det: http://bluebirdjs.com/docs/api/promise.promisify.html
