Promesas, pasar parámetros adicionales para luego encadenar

100

Una promesa, solo por ejemplo:

var P = new Promise(function (resolve, reject) {
  var a = 5;
  if (a) {
    setTimeout(function(){
      resolve(a);
    }, 3000);
  } else {
    reject(a);
  }
});

Después de llamar, entonces el método de la promesa:

P.then(doWork('text'));

La función doWork se ve así:

function doWork(data) {
  return function(text) {
    // sample function to console log
    consoleToLog(data);
    consoleToLog(b);
  }
}

¿Cómo puedo evitar devolver una función interna en doWork para obtener acceso a los datos de la promesa y los parámetros de texto? ¿Existen trucos para evitar la función interna?

usuario3110667
fuente
1
¿Por qué alguien renunciaría intencionalmente al curry ? ¿Para utilizar el espantoso bindmétodo? - que también es extremadamente lento.
@ftor No le entiendo, ¿podría proporcionar algún código para aclarar?
Roland

Respuestas:

86

Puede usar Function.prototype.bindpara crear una nueva función con un valor pasado a su primer argumento, como este

P.then(doWork.bind(null, 'text'))

y puedes cambiar doWorka,

function doWork(text, data) {
  consoleToLog(data);
}

Ahora, textestará realmente 'text'dentro doWorky dataserá el valor resuelto por la Promesa.

Nota: asegúrese de adjuntar un controlador de rechazo a su cadena de promesas.


Programa de trabajo: copia en vivo del REPL de Babel

function doWork(text, data) {
  console.log(text + data + text);
}

new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
      setTimeout(function () {
        resolve(a);
      }, 3000);
    } else {
      reject(a);
    }
  })
  .then(doWork.bind(null, 'text'))
  .catch(console.error);
los cuatro ojos
fuente
gracias, eso ayuda, antes probé doWork.call (esto, 'texto'), pero los datos fueron reemplazados por 'texto'
user3110667
2
callinvoca una función en el lugar, bindcrea una nueva función, sin embargo, ambos aceptan un contexto de ejecución como su primer argumento.
sdgluck
103

Quizás la respuesta más sencilla es:

P.then(function(data) { return doWork('text', data); });

O, dado que está etiquetado ecmascript-6, usando funciones de flecha:

P.then(data => doWork('text', data));

Encuentro esto más legible y no demasiado para escribir.

foque
fuente
5

Usa curry.

var P = new Promise(function (resolve, reject) {
    var a = 5;
    if (a) {
        setTimeout(function(){
            resolve(a);
        }, 3000);
    } else {
        reject(a);
    }
});

var curriedDoWork = function(text) {
    return function(data) {
        console.log(data + text);
    }
};

P.then(curriedDoWork('text'))
.catch(
    //some error handling
);
yks
fuente
b cuidado con esto, si crea curriedDoWorkuna promesa haciendo return new Promise()en la primera línea de esta función, la promesa se ejecuta tan pronto como llame curriedDoWork()(como lo hace en..then(curriedDoWork('text'))
Flame
@Flame: respuesta corta, para su conveniencia, puede envolver la promesa en una función, si lo desea.
Germain
@yks, podría haber indicado esta sintaxis que es bastante interesante const curriedWork = text => data => console.log (data + text)
germain
1
@germain ah sí, he visto este formulario antes, me encanta la programación funcional. Sin embargo, siento que las funciones de flecha se rompen en algunos navegadores, por lo que ahora tiendo a evitarlas.
yks
@yks, solo Internet Explorer no lo admite y nunca, debido a Edge, la última versión de Internet Explorer fue el 9 de diciembre de 2015. Sigamos ~
germain
0

Lodash ofrece una buena alternativa para esto exactamente.

 P.then(_.bind(doWork, 'myArgString', _));

 //Say the promise was fulfilled with the string 'promiseResults'

 function doWork(text, data) {
     console.log(text + " foo " + data);
     //myArgString foo promiseResults
 }

O, si desea que su función de éxito tenga solo un parámetro (los resultados de la promesa cumplida), puede utilizarlo de esta manera:

P.then(_.bind(doWork, {text: 'myArgString'}));

function doWork(data) {
    console.log(data + " foo " + this.text);
    //promiseResults foo myArgString
}

Esto se adjuntará text: 'myArgString'al thiscontexto dentro de la función.

JellyRaptor
fuente