Promises
Jesús Leganés-Combarro 'piranna'
piranna@gmail.com
Agosto 2018
Javascript
-
Asincrono y no bloqueante (recomendado)
- Ejecución no lineal (callbacks, eventos...)
- Ningún estandar en el lenguaje
- Librerias externas
- "Callback Hell"
const {mkdir, writeFile} = require('fs')
mkdir('path', function(error)
{
if(error && error.code !== 'EEXIST') return console.trace(error)
writeFile('path/file.txt', 'asdf', function(error)
{
if(error) return console.trace(error)
console.log('Profit!')
})
})
Que es un objeto `Promise`
const {promises: {mkdir, writeFile}} = require('fs')
mkdir('path')
.catch(function({code})
{
if(code !== 'EEXIST') throw error
})
.then(function()
{
return writeFile('path/file.txt', 'asdf')
})
.then(function()
{
console.log('Profit!')
},
console.trace)
- Incorporado al lenguaje
- Futures, Deferred...
- Envuelve un resultado, avisando cuando se haya producido
Estados
- pending, operación en curso
- fullfilled, terminó correctamente
- rejected, la operación falló
Métodos
- then(onFullfilled, onRejected)
- catch(onRejected)
- finally(onFinally)
Thenable objects
const thenable =
{
then(onFullfilled)
{
onFullfilled('asdf')
}
}
thenable.then(function(value)
{
console.log(value) // asdf
})
- (Casi) cualquier objeto con then() puede usarse como un Promise
- Promises / A+
- jQuery no es compatible
Creando promesas
const promise = new Promise(function(resolve, reject)
{
resolve('asdf')
})
promise.then(function(value)
{
console.log(value) // asdf
})
const promise = Promise.resolve('asdf')
promise.then(function(value)
{
console.log(value) // asdf
})
const promise = new Promise(function(resolve)
{
setTimeout(resolve, 1000, 'asdf')
})
promise.then(function(value)
{
console.log(value) // asdf, 1 second later
})
const button = new CoolButton()
const promise = new Promise(function(resolve)
{
button.once('click', resolve)
})
promise.then(function(value)
{
console.log('button clicked')
})
const {mkdir, writeFile} = require('fs')
const {promisify} = require('util')
promisify(mkdir)('path')
.catch(function({code})
{
if(code !== 'EEXIST') throw error
})
.then(function()
{
return promisify(writeFile)('path/file.txt', 'asdf')
})
.then(function()
{
console.log('Profit!')
},
console.trace)
Promesas encadenadas
Promise.resolve(1)
.then(function(value)
{
console.log(value) // 1
return 'asdf'
}
.then(function(value)
{
console.log(value) // asdf
// no devolvemos nada, la nueva promesa se resolvera con valor `undefined`
}
then() genera una nueva promesa
- return con un valor (por defecto undefined), la promesa resuelve
- throw una excepción, la promesa es rechazada
- return una promesa, se convierte en la promesa devuelta (completada o rechazada)
const promise1 = Promise.resolve(1)
const promise2 = promise1.then(function(value)
{
console.log(value) // 1
return 'asdf'
}
.then(function(value)
{
console.log(value) // asdf
}
promise1.then(function(value)
{
console.log(value) // 1 again, since `promise1` now has two binded callbacks
})
- Usar varios then() consecutivos NO vincula los callbacks a la promesa original, sino cada vez genera una nueva
- para vincular varios callbacks a una misma promesa, hacerlo directamente sobre ella
Control de flujo
const {promises: {mkdir, writeFile}} = require('fs')
mkdir('path')
.catch(function({code})
{
if(code !== 'EEXIST') throw error
})
.then(function()
{
return writeFile('path/file.txt', 'asdf')
})
.then(function()
{
console.log('Profit!')
},
console.trace)
Promise.all([
Promise.resolve(1),
2,
fetch('http://www.google.es')
.then(res => res.text())
])
.then(function([value1, value2, value3])
{
console.log(value1) // 1
console.log(value2) // 2
console.log(value3) // <html>... </html>
})
Promise.race([
fetch('http://www.google.es')
.then(res => res.text()),
new Promise(function(resolve, reject)
{
setTimeout(reject, 5000, 'timeout')
})
])
.then(function(html)
{
console.log(html) // <html>... </html>
},
function(error)
{
if(error !== 'timeout') throw error
console.log('Request timed out')
})
- all(array), resuelve a un array con los resultados de todas las promesas del array de entrada, o el error de la primera promesa que haya sido rechazada
- race(array), devuelve la primera promesa que haya sido resuelta o rechazada
function print23()
{
return new Promise(function(resolve)
{
setTimeout(function()
{
console.log(2)
resolve(3)
}, 1000)
})
}
function func()
{
console.log(1)
console.log(print23())
console.log(4)
return 5
}
console.log(func()) // 1, [object Promise], 4, 5, 2
async function func()
{
console.log(1)
console.log(await print23())
console.log(4)
return 5
}
func().then(console.log) // 1, 2, 3, 4, 5
Async / Await
function func()
{
console.log(1)
return print23()
.then(function(three)
{
console.log(three)
console.log(4)
return 5
})
}
func().then(console.log) // 1, 2, 3, 4, 5
- apariencia de código lineal en operaciones asincronas
- async, envuelve una función y devuelve una promesa que resuelve a su valor retornado
- await, para la ejecución de una función para continuarla después
Promises
By Jesús Leganés-Combarro
Promises
- 375