1. 什么是Promise?为什么需要它?
从最简单的例子开始- app.js
Code Example 1-最简单的promise:
let promiseToCleanTheRoom = new Promise(function(resolve,reject){
let isClean = true;
if(isClean){
resolve();
}
else {
reject();
}
})
promiseToCleanTheRoom.then(function(){
console.log('Room is clean');
}).catch(function(){
console.log('Room is not clean');
})
当isClean=true | false
时,输出:Room is clean | Room is not clean
如果不用Promise,应该怎么写?
let promiseToCleanTheRoom = function (successCallback, errorCallback) {
let isClean = true;
if (isClean) {
successCallback();
}
else {
errorCallback();
}
}
promiseToCleanTheRoom(function(){
console.log('Room is clean');
},function(){
console.log('Room is not clean');
})
可以看到,我们不得不把方法当做参数进行传递。
在这个例子中,使用和不使用Promise的区别不大,但如果遇到下面这种情况,估计就抓狂了:
setTimeout(function() {
setTimeout(function() {
setTimeout(function() {
// do something...
}, 1);
}, 1)
}, 1)
ok, 欢迎来到javascript 回调地狱,我猜你是回不去了
javascript callback hell
为加深印象,再看一段代码(promise官网例子):
function readJSONSync(filename) {
return JSON.parse(fs.readFileSync(filename, 'utf8'));
}
代码乍一看很正常,但如果这个文件非常大,或者假设硬盘非常非常慢,一秒只能读1kb呢??在javascript的单线程世界里,我们怕是要一直等下去了...
我们知道,这种情况叫做同步编程,方法名里的Sync
也证明了这一点。其它语言都有很好的多线程支持,比如c#的Thread。js处理多线程用的是方法回调:
function readJSON(filename, callback){
fs.readFile(filename, 'utf8', function (err, res){
if (err) return callback(err);
callback(null, JSON.parse(res));//此处有隐患
});
}
把callback传进去,就这么简单直接,有没有很眼熟?是的,express就是这个写法:
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
这里的next就是callback,前面的function也是。知道为什么express作者要开发koa了吧。为了躲开callback hell。
回到上面读json文件那个例子中我标出此处有隐患
的地方,如果这个地方json文件格式不合适,读取发生错误呢?(-ps:这种情况真的很多见),我们需要try catch错误;那么代码又变成下面这个样子:
function readJSON(filename, callback){
fs.readFile(filename, 'utf8', function (err, res){
if (err) return callback(err);
try {
res = JSON.parse(res);
} catch (ex) {
return callback(ex);
}
callback(null, res);
});
}
这样,callback函数就需要同时负责处理异常和正常数据。知道express的异常处理函数,第一个参数为什么必须是err了吧?
function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
2. 怎么使用Promise?
根据官方文档,Promise有以下3种状态:
- pending:初始状态
- fulfilled:成功状态
- rejected:失败状态
要使用promise我们首先得有一个promise,我们可以非常轻松的定义它:
function readFile(filename, enc){
return new Promise(function (fulfill, reject){
fs.readFile(filename, enc, function (err, res){
if (err) reject(err);
else fulfill(res);
});
});
}
可以看到,我们把生成promise对象的工作都交给了构造函数,同时传入fulfill, reject两个参数,它们将在合适的时候被调用。注意:我们没有传入callback 方法。
同时也注意到,readFile还是使用了callback啊?是的,要用Promise,就得所有的地方都用 Promise。对于 Node 的原生 API,需要进行二次封装。
使用promise很简单:
readFile('file.txt', 'utf8').then(function (res) {
console.log(res);
}).catch(function (err) {
console.log('errors:' + err);
})
小结:
- Promise 是对方法进行的一种封装,避免在js异步编程中将方法当做参数直接传递,从而有效避免了callback hell.
下次再说promise下集
网友评论