¿Cómo convierto una API de devolución de llamada existente en promesas?

747
Benjamin Gruenbaum 2014-03-20 12:47.

Quiero trabajar con promesas pero tengo una API de devolución de llamada en un formato como:

1. Carga de DOM u otro evento único:

window.onload; // set to callback
...
window.onload = function() {

};

2. Devolución de llamada sencilla:

function request(onChangeHandler) {
    ...
}
request(function() {
    // change happened
    ...
});

3. Devolución de llamada de estilo de nodo ("nodeback"):

function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
})

4. Una biblioteca completa con devoluciones de llamada de estilo de nodo:

API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

¿Cómo trabajo con la API en las promesas, cómo la "prometo"?

19 answers

769
Benjamin Gruenbaum 2014-03-20 12:47.

Las promesas tienen estado, comienzan como pendientes y pueden asentarse en:

  • cumplido, lo que significa que el cálculo se completó correctamente.
  • rechazado lo que significa que el cálculo falló.

Las funciones de devolución de promesas nunca deben lanzar , deben devolver rechazos en su lugar. Lanzar desde una función de devolución de promesa lo obligará a usar tanto a } catch { como a .catch. Las personas que utilizan API promisificadas no esperan que las promesas arrojen. Si no está seguro de cómo funcionan las API asíncronas en JS, consulte esta respuesta primero.

1. Carga de DOM u otro evento único:

Por lo tanto, crear promesas generalmente significa especificar cuándo se resuelven, es decir, cuándo pasan a la fase cumplida o rechazada para indicar que los datos están disponibles (y se puede acceder a ellos .then).

Con implementaciones de promesas modernas que admiten el Promiseconstructor como promesas nativas de ES6:

function load() {
    return new Promise(function(resolve, reject) {
        window.onload = resolve;
    });
}

Luego usaría la promesa resultante así:

load().then(function() {
    // Do things after onload
});

Con bibliotecas que admiten diferido (usemos $ q para este ejemplo aquí, pero también usaremos jQuery más adelante):

function load() {
    var d = $q.defer();
    window.onload = function() { d.resolve(); };
    return d.promise;
}

O con una API como jQuery, conectando un evento que ocurre una vez:

function done() {
    var d = $.Deferred();
    $("#myObject").once("click",function() {
        d.resolve();
    });
    return d.promise();
}

2. Devolución de llamada sencilla:

Estas API son bastante comunes ya que bueno… las devoluciones de llamada son comunes en JS. Veamos el caso común de tener onSuccessy onFail:

function getUserData(userId, onLoad, onFail) { …

Con implementaciones de promesas modernas que admiten el Promiseconstructor como promesas nativas de ES6:

function getUserDataAsync(userId) {
    return new Promise(function(resolve, reject) {
        getUserData(userId, resolve, reject);
    });
}

Con bibliotecas que admiten diferido (usemos jQuery para este ejemplo aquí, pero también usamos $ q arriba):

function getUserDataAsync(userId) {
    var d = $.Deferred();
    getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
    return d.promise();
}

jQuery también ofrece un $.Deferred(fn)formulario, que tiene la ventaja de permitirnos escribir una expresión que emule muy de cerca el new Promise(fn)formulario, de la siguiente manera:

function getUserDataAsync(userId) {
    return $.Deferred(function(dfrd) {
        getUserData(userId, dfrd.resolve, dfrd.reject);
    }).promise();
}

Nota: Aquí aprovechamos el hecho de que los métodos resolvey diferidos de jQuery rejectson "desmontables"; es decir. están vinculados a la instancia de jQuery.Deferred (). No todas las bibliotecas ofrecen esta función.

3. Devolución de llamada de estilo de nodo ("nodeback"):

Los callbacks de estilo de nodo (nodebacks) tienen un formato particular donde los callbacks son siempre el último argumento y su primer parámetro es un error. Primero prometamos uno manualmente:

getStuff("dataParam", function(err, data) { …

A:

function getStuffAsync(param) {
    return new Promise(function(resolve, reject) {
        getStuff(param, function(err, data) {
            if (err !== null) reject(err);
            else resolve(data);
        });
    });
}

Con diferidos, puede hacer lo siguiente (usemos Q para este ejemplo, aunque Q ahora admite la nueva sintaxis que debería preferir ):

function getStuffAsync(param) {
    var d = Q.defer();
    getStuff(param, function(err, data) {
        if (err !== null) d.reject(err);
        else d.resolve(data);
    });
    return d.promise;   
}

En general, no debe prometer cosas demasiado manualmente, la mayoría de las bibliotecas de promesas que se diseñaron con Node en mente, así como las promesas nativas en Node 8+, tienen un método integrado para promisionar nodos de respaldo. Por ejemplo

var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only

4. Una biblioteca completa con devoluciones de llamada de estilo de nodo:

Aquí no hay una regla de oro, las promistes una por una. Sin embargo, algunas implementaciones de promesa le permiten hacer esto de forma masiva, por ejemplo, en Bluebird, convertir una API de nodeback en una API de promesa es tan simple como:

Promise.promisifyAll(API);

O con promesas nativas en Node :

const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
                         .reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});

Notas:

  • Por supuesto, cuando estás en un .thenhandler no necesitas prometer cosas. Devolver una promesa de un .thenmanejador resolverá o rechazará con el valor de esa promesa. Lanzar desde un .thenmanejador también es una buena práctica y rechazará la promesa: esta es la famosa promesa de lanzar la seguridad.
  • En un onloadcaso real , debería usar en addEventListenerlugar de onX.
58
efkan 2017-01-03 03:19.

Hoy, puedo usar Promiseen Node.jsun método sencillo Javascript.

Un ejemplo simple y básico para Promise(con KISS way):

Código API asíncrono de Javascript simple :

function divisionAPI (number, divider, successCallback, errorCallback) {

    if (divider == 0) {
        return errorCallback( new Error("Division by zero") )
    }

    successCallback( number / divider )

}

Promise Código API de Javascript Async:

function divisionAPI (number, divider) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            return rejected( new Error("Division by zero") )
        }

        fulfilled( number / divider )

     })

}

(Recomiendo visitar esta hermosa fuente )

También Promisese puede usar con together async\awaitin ES7para hacer que el flujo del programa espere un fullfiledresultado como el siguiente:

function getName () {

    return new Promise(function (fulfilled, rejected) {

        var name = "John Doe";

        // wait 3000 milliseconds before calling fulfilled() method
        setTimeout ( 
            function() {
                fulfilled( name )
            }, 
            3000
        )

    })

}


async function foo () {

    var name = await getName(); // awaits for a fulfilled result!

    console.log(name); // the console writes "John Doe" after 3000 milliseconds

}


foo() // calling the foo() method to run the code

Otro uso con el mismo código usando el .then()método

function getName () {

    return new Promise(function (fulfilled, rejected) {

        var name = "John Doe";

        // wait 3000 milliseconds before calling fulfilled() method
        setTimeout ( 
            function() {
                fulfilled( name )
            }, 
            3000
        )

    })

}


// the console writes "John Doe" after 3000 milliseconds
getName().then(function(name){ console.log(name) })

Promisetambién se puede utilizar en cualquier plataforma basada en Node.js como react-native.

Bono : un método híbrido
(se supone que el método de devolución de llamada tiene dos parámetros como error y resultado)

function divisionAPI (number, divider, callback) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            let error = new Error("Division by zero")
            callback && callback( error )
            return rejected( error )
        }

        let result = number / divider
        callback && callback( null, result )
        fulfilled( result )

     })

}

El método anterior puede responder al resultado de los usos antiguos de devolución de llamada y Promesa.

Espero que esto ayude.

35
Siva Kannan 2017-08-12 01:31.

Antes de convertir una función como promesa en Node.JS

var request = require('request'); //http wrapped module

function requestWrapper(url, callback) {
    request.get(url, function (err, response) {
      if (err) {
        callback(err);
      }else{
        callback(null, response);             
      }      
    })
}


requestWrapper(url, function (err, response) {
    console.log(err, response)
})

Después de convertirlo

var request = require('request');

function requestWrapper(url) {
  return new Promise(function (resolve, reject) { //returning promise
    request.get(url, function (err, response) {
      if (err) {
        reject(err); //promise reject
      }else{
        resolve(response); //promise resolve
      }
    })
  })
}


requestWrapper('http://localhost:8080/promise_request/1').then(function(response){
    console.log(response) //resolve callback(success)
}).catch(function(error){
    console.log(error) //reject callback(failure)
})

En caso de que necesite manejar múltiples solicitudes

var allRequests = [];
allRequests.push(requestWrapper('http://localhost:8080/promise_request/1')) 
allRequests.push(requestWrapper('http://localhost:8080/promise_request/2'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/5'))    

Promise.all(allRequests).then(function (results) {
  console.log(results);//result will be array which contains each promise response
}).catch(function (err) {
  console.log(err)
});
23
Leo 2015-01-14 18:15.

No creo que la window.onloadsugerencia de @Benjamin funcione todo el tiempo, ya que no detecta si se llama después de la carga. Eso me ha mordido muchas veces. Aquí hay una versión que siempre debería funcionar:

function promiseDOMready() {
    return new Promise(function(resolve) {
        if (document.readyState === "complete") return resolve();
        document.addEventListener("DOMContentLoaded", resolve);
    });
}
promiseDOMready().then(initOnLoad);
15
Gian Marco 2017-05-31 20:46.

Node.js 8.0.0 incluye una nueva util.promisify()API que permite que las API de estilo de devolución de llamada de Node.js estándar se incluyan en una función que devuelve una promesa. A continuación se muestra un ejemplo de uso de util.promisify().

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

readFile('/some/file')
  .then((data) => { /** ... **/ })
  .catch((err) => { /** ... **/ });

Ver soporte mejorado para promesas

14
Bruno 2017-05-16 19:35.

En la versión candidata para Node.js 8.0.0, hay una nueva utilidad, util.promisify(he escrito sobre util.promisify ), que encapsula la capacidad de prometer cualquier función.

No es muy diferente de los enfoques sugeridos en las otras respuestas, pero tiene la ventaja de ser un método central y no requiere dependencias adicionales.

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

Entonces tienes un readFilemétodo que devuelve un nativo Promise.

readFile('./notes.txt')
  .then(txt => console.log(txt))
  .catch(...);
7
Apoorv 2016-06-21 03:38.

Puede usar promesas nativas de JavaScript con Node JS.

Enlace de código de My Cloud 9: https://ide.c9.io/adx2803/native-promises-in-node

/**
* Created by dixit-lab on 20/6/16.
*/

var express = require('express');
var request = require('request');   //Simplified HTTP request client.


var app = express();

function promisify(url) {
    return new Promise(function (resolve, reject) {
        request.get(url, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                resolve(body);
            }
            else {
                reject(error);
            }
        })
    });
}

//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
    //get the post with post id 100
    promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
        var obj = JSON.parse(result);
        return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
    })
    .catch(function (e) {
        console.log(e);
    })
    .then(function (result) {
        res.end(result);
    })
})

var server = app.listen(8081, function () {
    var host = server.address().address
    var port = server.address().port

    console.log("Example app listening at http://%s:%s", host, port)
})

//run webservice on browser : http://localhost:8081/listAlbums
7
daviddavis 2016-11-28 17:07.

Con JavaScript simple y antiguo, aquí hay una solución para prometer una devolución de llamada de API.

function get(url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.addEventListener('readystatechange', function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    console.log('successful ... should call callback ... ');
                    callback(null, JSON.parse(xhr.responseText));
                } else {
                    console.log('error ... callback with error data ... ');
                    callback(xhr, null);
                }
            }
        });
        xhr.send();
    }

/**
     * @function promisify: convert api based callbacks to promises
     * @description takes in a factory function and promisifies it
     * @params {function} input function to promisify
     * @params {array} an array of inputs to the function to be promisified
     * @return {function} promisified function
     * */
    function promisify(fn) {
        return function () {
            var args = Array.prototype.slice.call(arguments);
            return new Promise(function(resolve, reject) {
                fn.apply(null, args.concat(function (err, result) {
                    if (err) reject(err);
                    else resolve(result);
                }));
            });
        }
    }

var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
        // corresponds to the resolve function
        console.log('successful operation: ', data);
}, function (error) {
        console.log(error);
});
6
Jason Loveman 2015-04-08 08:30.

La biblioteca Q de kriskowal incluye funciones de devolución de llamada a promesa. Un método como este:

obj.prototype.dosomething(params, cb) {
  ...blah blah...
  cb(error, results);
}

se puede convertir con Q.ninvoke

Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});
4
user1852503 2016-08-04 14:45.

Cuando tiene algunas funciones que reciben una devolución de llamada y desea que devuelvan una promesa, puede usar esta función para hacer la conversión.

function callbackToPromise(func){

    return function(){

        // change this to use what ever promise lib you are using
        // In this case i'm using angular $q that I exposed on a util module

        var defered = util.$q.defer();

        var cb = (val) => {
            defered.resolve(val);
        }

        var args = Array.prototype.slice.call(arguments);
        args.push(cb);    
        func.apply(this, args);

        return defered.promise;
    }
}
4
Paul Spaulding 2017-04-13 06:48.

Bajo el nodo v7.6 + que tiene promesas integradas y asincrónicas:

// promisify.js
let promisify = fn => (...args) =>
    new Promise((resolve, reject) =>
        fn(...args, (err, result) => {
            if (err) return reject(err);
            return resolve(result);
        })
    );

module.exports = promisify;

Cómo utilizar:

let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);

async function myAsyncFn(path) {
    let entries = await readdirP(path);
    return entries;
}
3
Do Async 2017-10-13 12:19.

En Node.js 8 puede promisificar métodos de objetos sobre la marcha usando este módulo npm:

https://www.npmjs.com/package/doasync

Utiliza util.promisify y Proxies para que sus objetos permanezcan sin cambios. La memorización también se realiza con el uso de WeakMaps). Aquí hay unos ejemplos:

Con objetos:

const fs = require('fs');
const doAsync = require('doasync');

doAsync(fs).readFile('package.json', 'utf8')
  .then(result => {
    console.dir(JSON.parse(result), {colors: true});
  });

Con funciones:

doAsync(request)('http://www.google.com')
  .then(({body}) => {
    console.log(body);
    // ...
  });

Incluso puede usar nativo cally applypara vincular algo de contexto:

doAsync(myFunc).apply(context, params)
  .then(result => { /*...*/ });
2
Nicolas Zozol 2017-01-23 03:22.

Puede usar Promise nativo en ES6, por ejemplo, tratar con setTimeout:

enqueue(data) {

    const queue = this;
    // returns the Promise
    return new Promise(function (resolve, reject) {
        setTimeout(()=> {
                queue.source.push(data);
                resolve(queue); //call native resolve when finish
            }
            , 10); // resolve() will be called in 10 ms
    });

}

En este ejemplo, la Promesa no tiene ninguna razón para fallar, por reject()lo que nunca se llama.

2
jituanlin 2017-07-31 03:39.

La función de estilo de devolución de llamada siempre es así (casi todas las funciones en node.js tienen este estilo):

//fs.readdir(path[, options], callback)
fs.readdir('mypath',(err,files)=>console.log(files))

Este estilo tiene la misma característica:

  1. la función de devolución de llamada se pasa por el último argumento.

  2. la función de devolución de llamada siempre acepta el objeto de error como primer argumento.

Entonces, podría escribir una función para convertir una función con este estilo como este:

const R =require('ramda')

/**
 * A convenient function for handle error in callback function.
 * Accept two function res(resolve) and rej(reject) ,
 * return a wrap function that accept a list arguments,
 * the first argument as error, if error is null,
 * the res function will call,else the rej function.
 * @param {function} res the function which will call when no error throw
 * @param {function} rej the function which will call when  error occur
 * @return {function} return a function that accept a list arguments,
 * the first argument as error, if error is null, the res function
 * will call,else the rej function
 **/
const checkErr = (res, rej) => (err, ...data) => R.ifElse(
    R.propEq('err', null),
    R.compose(
        res,
        R.prop('data')
    ),
    R.compose(
        rej,
        R.prop('err')
    )
)({err, data})

/**
 * wrap the callback style function to Promise style function,
 * the callback style function must restrict by convention:
 * 1. the function must put the callback function where the last of arguments,
 * such as (arg1,arg2,arg3,arg...,callback)
 * 2. the callback function must call as callback(err,arg1,arg2,arg...)
 * @param {function} fun the callback style function to transform
 * @return {function} return the new function that will return a Promise,
 * while the origin function throw a error, the Promise will be Promise.reject(error),
 * while the origin function work fine, the Promise will be Promise.resolve(args: array),
 * the args is which callback function accept
 * */
 const toPromise = (fun) => (...args) => new Promise(
    (res, rej) => R.apply(
        fun,
        R.append(
            checkErr(res, rej),
            args
        )
    )
)

Para más conciso, el ejemplo anterior usó ramda.js. Ramda.js es una excelente biblioteca para programación funcional. En el código anterior, usamos su aplicar (como javascript function.prototype.apply) y agregar (como javascript function.prototype.push). Por lo tanto, podríamos convertir la función de estilo de devolución de llamada en una función de estilo de promesa ahora:

const {readdir} = require('fs')
const readdirP = toPromise(readdir)
readdir(Path)
    .then(
        (files) => console.log(files),
        (err) => console.log(err)
    )

La función toPromise y checkErr es propiedad de la biblioteca berserk , es una bifurcación de biblioteca de programación funcional de ramda.js (creada por mí).

Espero que esta respuesta te sea útil.

2
onmyway133 2018-10-10 03:35.

Puedes hacer algo como esto

// @flow

const toPromise = (f: (any) => void) => {
  return new Promise<any>((resolve, reject) => {
    try {
      f((result) => {
        resolve(result)
      })
    } catch (e) {
      reject(e)
    }
  })
}

export default toPromise

Entonces úsalo

async loadData() {
  const friends = await toPromise(FriendsManager.loadFriends)

  console.log(friends)
}
1
Pujan 2017-10-18 13:56.

es6-promisify convierte funciones basadas en devolución de llamada en funciones basadas en promesas.

const promisify = require('es6-promisify');

const promisedFn = promisify(callbackedFn, args);

Ref: https://www.npmjs.com/package/es6-promisify

1
loretoparisi 2017-11-30 13:34.

Mi versión promisoria de una callbackfunción es la Pfunción:

var P = function() {
  var self = this;
  var method = arguments[0];
  var params = Array.prototype.slice.call(arguments, 1);
  return new Promise((resolve, reject) => {
    if (method && typeof(method) == 'function') {
      params.push(function(err, state) {
        if (!err) return resolve(state)
        else return reject(err);
      });
      method.apply(self, params);
    } else return reject(new Error('not a function'));
  });
}
var callback = function(par, callback) {
  var rnd = Math.floor(Math.random() * 2) + 1;
  return rnd > 1 ? callback(null, par) : callback(new Error("trap"));
}

callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))

P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))

La Pfunción requiere que la firma de devolución de llamada sea callback(error,result).

1
Mzndako 2019-06-22 00:38.

A continuación se muestra la implementación de cómo una función (API de devolución de llamada) se puede convertir en una promesa.

function promisify(functionToExec) {
  return function() {
    var array = Object.values(arguments);
    return new Promise((resolve, reject) => {
      array.push(resolve)
      try {
         functionToExec.apply(null, array);
      } catch (error) {
         reject(error)
      }
    })
  }
}

// USE SCENARIO

function apiFunction (path, callback) { // Not a promise
  // Logic
}

var promisedFunction = promisify(apiFunction);

promisedFunction('path').then(()=>{
  // Receive the result here (callback)
})

// Or use it with await like this
let result = await promisedFunction('path');

1
Josiah Nyarega 2020-09-25 08:28.

Desde el futuro 😄

Una función genérica simple que uso normalmente.

const promisify = (fn, ...args) => {
  return new Promise((resolve, reject) => {
    fn(...args, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data);
    });
  });
};

Cómo usarlo

   promisify(fn, arg1, arg2)

Probablemente no esté buscando esta respuesta, pero esto le ayudará a comprender el funcionamiento interno de las utilidades disponibles

Related questions

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.

Atún como Oh, Hello llega a Netflix

Atún como Oh, Hello llega a Netflix

Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.

Actualice a un Sonicare por tan solo $ 30

Actualice a un Sonicare por tan solo $ 30

¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language