夜话Promise(上)

作者: Angeladaddy | 来源:发表于2018-01-26 00:18 被阅读31次

    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下集

    相关文章

      网友评论

        本文标题:夜话Promise(上)

        本文链接:https://www.haomeiwen.com/subject/jdgbaxtx.html