A Quick Introduction
by Soares Chen
A talk.js presentation
October 2014
var readJson = function(filename, callback) {
fs.readFile(filename, function(err, content) {
if(err) return callback(err)
try {
var json = JSON.parse(content)
} catch(err) {
return callback(err)
}
return callback(null, json)
})
}
if(err) return callback(err)
var readFile = function(filename) {
return new Promise(function(resolve, reject) {
fs.readFile(filename, function(err, content) {
if(err) return reject(err)
resolve(content)
})
})
}
// promise.then(onFulfilled, onRejected)
readFile('foo.json').then(function(content) {
...
}, function(err) {
...
})
// promise.then(null, onRejected)
// = promise.catch(onRejected)
readFile('foo.json').then(function(content) {
...
}).catch(function(err) {
...
})
var foo = function() {
return new Promise(function(resolve, reject) {
resolve('foo')
resolve('bar')
reject(new Error())
})
}
foo().then(function(result) {
// prints 'foo() returns foo'
console.log('foo() returns', result)
})
var bar = function() {
return new Promise(function(resolve, reject) {
reject(new Error('error creating bar'))
})
}
bar().then(function(result) {
// should never print
console.log('bar result:', result)
}, function(err) {
console.log('oops! failed to create bar')
})
var baz = function() {
return new Promise(function(resolve, reject) {
throw new Error('Yay! Can throw again!')
})
}
bar().catch(function(err) {
console.log('Caught error thrown in baz()')
})
var baz = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
throw new Error('Async error is not caught!')
resolve('never reach')
}, 1000)
})
}
bar().then(function(result) {
console.log('Neither result nor')
}, function(err) {
console.log('error callback will ever be called')
})
var foo = function() {
return Promise.resolve('foo')
}
var bar = function() {
return Promise.reject(new Error('bar error')
}
var baz = function() {
return Promise.resolve(
Promise.reject(new Error('baz error'))
}
baz().then(function(result) {
console.log('never reach')
}, function(err) {
console.log('final resolved value of baz() is error')
})
var cached = null
var expensiveTask = function() {
if(cached) return Promise.resolve(cached)
return doExpensiveTask().then(function(result) {
cached = result
return result
})
}
var compose = function(f1, f2) {
return function() {
return Promise.resolve(f2()).then(f1)
}
}
// Sync version
baz(bar(foo(123)))
// Promised version
foo(123).then(bar).then(baz)
// Equivalent to
foo(123).then(function(fooResult) {
return bar(barResult).then(function(barResult) {
return baz(barResult)
})
})
// Useful Example
readFile('foo.json').then(JSON.parse)
.then(function(json) { ... })
foo(123).then(function(fooResult) {
return bar(345, fooResult).then(function(barResult) {
return {
foo: fooResult,
bar: barResult
}
})
}).then(function(result) {
// Will print { "foo": ..., "bar": ... }
console.log('result:', result)
})
foo(123).then(function(fooResult) {
throw new Error('foo error')
})
.then(bar) // bar is never called
.catch(function(err) {
console.log('Will catch all possible errors')
// More commonly should rethrow error
// throw err
return 'recovered value'
})
.then(function(result) {
// will print 'recovered value'
console.log('final result:' result)
})
foo(123).then(function(fooResult) {
throw new Error('Error is ignored')
}, function(err) {
console.log('will only catch foo() errors')
})
var readFiles = function(filenames) {
return Promise.all(filenames.map(readFile))
}
var array = [1, 2, 3]
// ES5
var mapped = array.map(function(x) {
return x*x
})
// ES6
var es6 = array.map(x => x*x)
var readFile = filename =>
new Promise((resolve, reject) =>
fs.readFile(filename, (err, filepath) => {
if(err) return reject(err)
resolve(filepath)
})
var timeout = time =>
new Promise(resolve =>
setTimeout(resolve, time))
timeout(1000).then(() => {
...
})
var readFile = promisify(fs.readFile)
readFile(filename).then(content => {
...
})
var promisify = fn =>
(...args) =>
createPromise((resolve, reject) =>
fn(...args, (err, result) =>
err ? reject(err) : resolve(result)))
var memcachedAsync = new Memcached(...)
var memcachedPromised = promisifyMethods(
memcachedAsync, ['get', 'set', ...])
memcached.get('foo').then(data => {
...
})
var promisifyMethod = (object, method) =>
promisify((...args) =>
object[method](...args))
var promisifyMethods = (object, methods) =>
methods.reduce((result, method) => {
result[method] = promisifyMethod(object, method)
return result
}, { })
doSomeComplicatedTasks().then(() => {
...
}).catch(err =>
... // try to recover
throw new Error('error in middle of recovery!')
console.log('never reach')
})
doSomeComplicatedTasks().then(() => {
...
}).catch(err => {
... // try to recover
throw new Error('error in middle of recovery!')
console.log('never reach')
}).catch(err => {
console.log('Something went seriously wrong! Exiting..')
process.exit(1)
})
var readJson = async function(filename) {
var content = await readFile(filename)
return JSON.parse(content)
}
var readJson = async(function*(filename) {
var content = yield readFile(filename)
return JSON.parse(content)
})
var runAsync = gen => {
var doNext = action => {
try {
var { done, value } = action()
} catch(err) {
return Promise.reject(err)
}
if(done) return value
return Promise.resolve(value).then(
result => doNext(() => gen.next(result)),
err => doNext(() => gen.throw(err)))
}
return Promise.resolve(doNext(() => gen.next()))
}
var async = fn =>
(...args) => runAsync(fn(...args))
// Using for loop
var readJsons = async(function*(filenames) {
var results = []
for(var i=0; i<filenames.length; i++) {
var content = yield readFile(filenames[i])
results[i] = JSON.parse(content)
}
return results
})
// Can't use Array.map()
var readJsons = async(function*(filenames) {
return filenames.map(function() {
// Error: invalid keyword yield
var content = yield readFile(filename)
return JSON.parse(content)
})
})
var readJsons = async(function*(filenames) {
var jsons = yield Promise.all(filenames.map(
async(function*(filename) {
var content = yield readFile(filename)
return JSON.parse(content)
})))
return jsons
})
Soares Chen
soares.chen@gmail.com
https://github.com/soareschen