我们可以通过全局构造函数Promise
来创建promise对象:
const myPromise = new Promise()
Promise
构造函数接受一个回调函数做为参数,而回调函数又接受两个参数;第一个参数用来收集或者捕获异步操作的结果,第二个参数用来捕获错误:
const myPromise = new Promise(function(resolve, reject) {
if (someError) {
reject(new Error(someError))
} else {
resolve('ok')
}
})
就像之前我们提到的,当 promise 对象resolved
,我们可以使用then
方法获取异步操作结果;当 promise 对象rejected
时,我们使用catch
方法处理错误:
myPromise
.then(function(result) {
console.log(result)
})
.catch(function(error) {
console.log(error)
})
值得一提的是,我们将任何异步任务包装到promise中。例如,fs.readFile
是一个用来异步读取文件内容的方法,我们通过下面的方式使用 fs.readFile
:
fs.readFile('some-file.txt', 'utf-8', function(error, content) {
if (error) {
return console.log(error)
}
console.log(content)
})
我们可以创建一个叫做readFile
的函数来调用fs.readFile
,读取文件内容,当读取正常时,我们使用文件内容resolve
promise对象,或者使用错误信息来reject
promise对象:
code/promises/wrap-readfile1.js
const fs = require('fs')
function readFile(file, format) {
format = format || 'utf-8'
function handler(resolve, reject) {
fs.readFile(file, format, function(err, content) {
if (err) {
return reject(err)
}
return resolve(content)
})
}
const promise = new Promise(handler)
return promise
}
我们还可以对上面的代码进行简化:
code/promises/wrap-readfile2.js
const fs = require('fs')
function readFile(file, format = 'utf-8') {
return new Promise((resolve, reject) => {
fs.readFile(file, format, (err, content) => {
if (err) return reject(err)
resolve(content)
})
})
}
现在,我们可以很方便的使用上面的函数异步读取文件内容了,使用then
方法获取异步结果,使用catch
方法处理错误:
readFile('./example.txt')
.then(content => console.log(content))
.catch(err => console.log(err))
甚至,我们还可以使用Node 8中引进的util.promisify
方法来进一步简化我们的代码:
code/promises/promisify-example.js
const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)
readFile('./example.txt', 'utf-8')
.then(content => console.log(content))
.catch(err => console.log(err))
util.promisify
方法接受一个遵循Node回调函数约定的函数,并把它变成基于 promise 的版本。你肯定会感到疑惑,为什么Node不把所有的方法都变成基于promise的,而要这样多此一举?底层Node方法都不是基于promise的,因为promise只是回调函数的上层抽象而已。是否使用这种上层抽象解决异步问题,应该交给开发者自行决定。