只为那句承诺-大话Promise

你们周末好,要说最近几年什么语言大红大紫,当属JavaScript了。话说虽然是10天就创造出的语言,可是人家能文能武。web前端天然没必要多说了,各类框架你方登罢我上场,前两年仍是Angular一统天下,这两年React又是大红大紫,还有Vue最近异军突起,好不红火。要是仅仅是前端也就算了,可是因为Node.js人家在后台也能写,React Native的出现让人家移动端也能作。好吧,还有硬件上也出现Ruff方案,好像硬件上也能写了。真是让人感受挺有意思的事情。前端

图表君上边叨叨了这么多,难道是为JavaScript唱赞歌的吗?呵呵,其实并非。只是最近由于在用上篇文章介绍的AWS Lambda。Lambda如今只支持Java,Node.js,Python。最终选择了Node.js进行开发,不可避免的要牵扯到异步操做的问题。那么今天就来聊聊JavaScript中的Promise。es6

什么是Promise

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。web

所谓Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise是一个对象,从它能够获取异步操做的消息。Promise提供统一的API,各类异步操做均可以用一样的方法进行处理。编程

上面是Promise的一个定义,引自阮一峰的ES6标准入门一书。S6标准入门。多说一句,目前的JavaScript项目不管是前台或者是后台,都应该采用ES6的标准语法来写,ES6让JavaScript的书写更加的清晰和规范。数组

基本用法

如何来构造一个promise对象呢?ES6中提供了原生Promise可使用。promise

var promise = new Promise(function(resolve, reject) {
  // ... here is some code

  if (/* 异步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

上面的例子给出了new一个promise对象的方法,Promise的构造函数接受一个函数做为参数传入,这个函数的两个参数,reject和resolve是JavaScript自己提供的两个函数。
一个promise对象有三个状态分别是,pending,resolved,rejected。resolve函数能够将pending状态转变为resolved状态。reject函数能够讲pending状态转变了rejected状态。对象的状态不受外界的影响,一样也是promise名字的由来。外部你拿着个人一个承诺,一会我会告诉你个人状态。ruby

promise对象经过then方法来添加回调函数。例如这样微信

promise.then(data=> console.log(data), err=> console.log(err));

当promise被resolved的时候,就会把data log出来。当promise被rejected的时候,err就会被log出来。
看上去好像是挺简单的,的确Promise的应用使得异步的操做,以同步的形式表现出来。当发生错误的时候能够经过catch方法,来定义回调函数。并发

怎么用

上边都是一些干巴巴的定义,那么到底该怎么用呢?Promise又怎么样的解决了问题呢,下边咱们看一个例子。假设下边一个场景,咱们一个服务,从一个外边service获取数据,而后写到一个db里,或者一个存储里,最后在把存储的状态龙出来,那么若是没有promise是怎么写的呢?可能会是这样。框架

getData(function (value1) {
  storeToDb(value1, function(value2) {
    logStore(value2, function(value3) {
      //...
    });
  });
});

传统的回调的写法,这样使得代码逻辑混乱在一块儿。再想一想若是再加上错误处理的状况,更是酸爽。那么用promise来写会怎么样呢?看下边这样的代码

function getData(){
    return new Promise((resolve,reject) =>{
        // ... send request to get data
        
        if(/* get successfully*/){
            resolve(data)
        }else{
            reject(err)
        }
    })
}

function storeData(data){
    return new Promise((resolve,reject)=>{
        // ... store the data
        
        if(/*store successfully*/){
            resolve(data)
        }else{
            reject(err)
        }
    })
}


getData()
    .then(data => storeData(data))
    .then(data => console.log('the process is done',data));
    .catch(err => console.error('there is the err',err));

这样写是否是就是很清楚了,先getData,而后再storeData,最后将此次运行的状况log了出来,其中有任何的问题,在catch中均可以Catch出来。代码的逻辑以同步的方式获得了体现。咱们来看看若是是其余语言会怎么写,下边是个ruby的语言的例子

def get_data 
    // ...send request
    
    if /*get successfully */
        return data
    else
        raise GetDataError
    end
end


def store_data
    // ...save to db
    
    if /*save successfully */
        return data
    else
        raise StoreDataError
    end
end


/*Main Logic*/
begin
    request_data = get_data
    db_data = store_data request_data
    p "here is the store data #{db_data}"
rescue e
    p "here is some errors #{e}"
end

咱们对比两个例子,能够看到在使用的Promise后让JavaScript的异步方式的编程模式更将清楚,也更加让人容易理解。

因为JavaScript的执行环境是单线程的,因此大量采用了异步的方式来进行编程,这使得咱们写起代码并不十分符合咱们通常的习惯。可是Promise的出现让这种问题能获得必定程度的缓解。

可是异步操做异步操做的好处,好比上边的那个例子,若是咱们想要作的同时并发10个操做,那个在ruby或者其余语言中中就要启多个线程来进行。可是JavaScript就彻底没有这个问题。只要简单的loop下就好了。

可是若是咱们想要在这10个操做完成后根据返回的状态作点其余操做该怎么作呢?这时候用Promise.all就是最好的了。

let p = Promise.all([p1, p2, p3]);

Promise.all接受数组做为参数传入,每一个元素都是一个promise对象。只要全部子promise都resolved之后,p才会被resolved。只要有一个被rejected,这个p就会被rejected。可是有一点是这些子promise之间并不会有顺序的关系。再来看一个例子:

var guid = 0;
function run() {
  guid++;
  var id = guid;
  return new Promise(resolve => {
    setTimeout(function () {
      console.log(id);
      resolve(id);
    }, (Math.random() * 1.5 | 0) * 1000);
  });
}

var promises = Array.from({ length: 10 }, run);
Promise.all(promises)

OUTPUT:

2
3
5
6
7
8
10
1
4
9

从此次的output能够看到,promise之间并无顺序执行,其实是并发的。那么如何让这些promise是顺序执行呢?留个你们本身思考下,下篇文章,咱们揭晓。或者能够联系图表君,私下告诉你答案哦。
ps,固然也能够用一些第三方的库和方案,例如(async)来实现顺序操做,可是代码的乐趣不就是作些思惟挑战吗:)


原创文章,欢迎转发,但请标明出处。欢迎关注图表君的公众号,一块儿成长。在微信中搜索 “多彩数据” 或者 “Data_Visualization”

图片描述

相关文章
相关标签/搜索