I want to understand why in the below example, the "call" method was used.
loadScript
is a function that appends a script tag to a document, and has an optional callback function.
promisify
returns a wrapper function that in turn returns a promise, effectively converting `loadScript' from a callback-based function to a promise based function.
function promisify(f) {
return function (...args) { // return a wrapper-function
return new Promise((resolve, reject) => {
function callback(err, result) { // our custom callback for f
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // append our custom callback to the end of f arguments
f.call(this, ...args); // call the original function
});
};
}
// usage:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
loadScript()
:
function loadScript(src, callback) {
let script = document.createElement("script");
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`Script load error for ${src}`));
document.head.append(script);
}
I understand that call
is used to force a certain context during function call, but why not use just use f(...args)
instead of f.call(this, ...args)
?
CodePudding user response:
promisify
is a general-purpose function. Granted, you don't care about this
in loadScript
, but you would if you were using promisify
on a method. So this works:
function promisify(f) {
return function (...args) { // return a wrapper-function
return new Promise((resolve, reject) => {
function callback(err, result) { // our custom callback for f
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // append our custom callback to the end of f arguments
f.call(this, ...args); // call the original function
});
};
}
class Example {
constructor(a) {
this.a = a;
}
method(b, callback) {
const result = this.a b;
setTimeout(() => callback(null, result), 100);
}
}
(async () => {
try {
const e = new Example(40);
const promisifiedMethod = promisify(e.method);
const result = await promisifiedMethod.call(e, 2);
console.log(result);
} catch (error) {
console.error(error);
}
})();
That wouldn't work if promisify
didn't use the this
that the function it returns receives:
function promisifyNoCall(f) {
return function (...args) { // return a wrapper-function
return new Promise((resolve, reject) => {
function callback(err, result) { // our custom callback for f
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // append our custom callback to the end of f arguments
f(...args); // call the original function *** changed
});
};
}
class Example {
constructor(a) {
this.a = a;
}
method(b, callback) {
const result = this.a b;
setTimeout(() => callback(null, result), 100);
}
}
(async () => {
try {
const e = new Example(40);
const promisifiedMethod = promisifyNoCall(e.method);
const result = await promisifiedMethod.call(e, 2);
console.log(result);
} catch (error) {
console.error(error);
}
})();