摘要:什么是是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大。函数可以将状态转变为状态。对象通过方法来添加回调函数。当发生错误的时候可以通过方法,来定义回调函数。接受数组作为参数传入,每个元素都是一个对象。
大家周末好,要说最近几年什么语言大红大紫,当属JavaScript了。话说虽然是10天就创造出的语言,但是人家能文能武。web前端自然不必多说了,各种框架你方登罢我上场,前两年还是Angular一统天下,这两年React又是大红大紫,还有Vue最近异军突起,好不红火。要是仅仅是前端也就算了,但是由于Node.js人家在后台也能写,React Native的出现让人家移动端也能做。好吧,还有硬件上也出现Ruff方案,好像硬件上也能写了。真是让人感觉挺有意思的事情。
图表君上边叨叨了这么多,难道是为JavaScript唱赞歌的吗?呵呵,其实并不是。只是最近因为在用上篇文章介绍的AWS Lambda。Lambda现在只支持Java,Node.js,Python。最终选择了Node.js进行开发,不可避免的要牵扯到异步操作的问题。那么今天就来聊聊JavaScript中的Promise。
什么是PromisePromise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
上面是Promise的一个定义,引自阮一峰的ES6标准入门一书。S6标准入门。多说一句,目前的JavaScript项目无论是前台或者是后台,都应该采用ES6的标准语法来写,ES6让JavaScript的书写更加的清晰和规范。
基本用法如何来构造一个promise对象呢?ES6中提供了原生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名字的由来。外部你拿着我的一个承诺,一会我会告诉你我的状态。
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”
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/80707.html
摘要:有点基础的人一定都知道,命令会将源文件编译成字节码文件,即文件,其中就包含了大量的字节码指令。关于字节码指令的分类,可以从两个维度进行一是指令的功能,二是指令操作的数据类型。 前言 随着Java开发技术不断被推到新的高度,对于Java程序员来讲越来越需要具备对更深入的基础性技术的理解,比如Java字节码指令。不然,可能很难深入理解一些时下的新框架、新技术,盲目一味追新也会越来越感乏力。...
摘要:理解承诺有两个部分。如果异步操作成功,则通过的创建者调用函数返回预期结果,同样,如果出现意外错误,则通过调用函数传递错误具体信息。这将与理解对象密切相关。这个函数将创建一个,该将在到秒之间的随机数秒后执行或。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:理解承诺有两个部分。如果异步操作成功,则通过的创建者调用函数返回预期结果,同样,如果出现意外错误,则通过调用函数传递错误具体信息。这将与理解对象密切相关。这个函数将创建一个,该将在到秒之间的随机数秒后执行或。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:只要指定过回调函数,这些事件发生时就会进入任务队列,等待主线程读取。三主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为事件循环。 一、任务队列 同步任务与异步任务的由来 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。 如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候C...
摘要:就算改变已经发生了,即使再对对象添加回调函数,也会立即得到这个结果。方法接收个参数,第一个参数是状态的回调函数,第二个参数可选是状态的回调函数。简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。 在ECMAScript 6标准中,Promise被正式列为规范,Promise,字面意思就是许诺,承诺,嘿,听着是不是很浪漫的说?我们来探究一下这个浪...
阅读 3648·2021-10-09 09:58
阅读 1187·2021-09-22 15:20
阅读 2495·2019-08-30 15:54
阅读 3509·2019-08-30 14:08
阅读 886·2019-08-30 13:06
阅读 1817·2019-08-26 12:16
阅读 2678·2019-08-26 12:11
阅读 2507·2019-08-26 10:38