Quiero entender por qué en el siguiente ejemplo, se utilizó el método de "llamada".
loadScript es una función que agrega una etiqueta de secuencia de comandos a un documento y tiene una función de devolución de llamada opcional.
promisify devuelve una función contenedora que a su vez devuelve una promesa, convirtiendo efectivamente 'loadScript' de una función basada en devolución de llamada a una función basada en promesa.
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); } Entiendo que la call se usa para forzar un cierto contexto durante la llamada a la función, pero ¿por qué no usar f(...args) en lugar de f.call(this, ...args) ?
promisify es una función de propósito general . De acuerdo, no le importa this en loadScript , pero lo haría si estuviera usando promisify en un método. Así que esto funciona:
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); } })(); Eso no funcionaría si promisify no usara this que recibe la función que devuelve:
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); } })();