JavaScript Promises
上篇文章介绍了JavaScript异步机制,请看这里。
JavaScript异步机制带来的问题
JavaScript异步机制的主要目的是处理非阻塞,在交互的过程中,会需要一些IO操作(比如Ajax请求,文件加载,Node.js中的文件读取等),如果这些操作是同步的,就会阻塞其它操作。
异步机制虽然带来了许多好处,但同时也存在一些不如意的地方。
代码可读性
这样的代码读起来简直累觉不爱啊~~~
operation1(function(err, result) { operation2(function(err, result) { operation3(function(err, result) { operation4(function(err, result) { operation5(function(err, result) { // do sth. }) }) }) }) })
流程控制
异步机制使得流程控制变的有些困难,比如,在N个for循环中的回调函数执行完成之后再做某些事情:
var data = []; fs.readdir(path, function (err, files) {if (err) {console.log(err)} else {for (var i in files) {(function (i) {fs.stat(path + '/' + files[i], function (err, stats) {if (err) {console.log(err)} else {o = {"fileName": files[i].slice(0, -5),"fileTime": stats.mtime.toString().slice(4, 15)};data.push(o);}})})(i);}} }); var html = template('templates/main', data); res.writeHead(200, {'Content-Type': 'text/html; charset="UTF-8"'}); res.write(html); res.end();
上面的代码不能获得预期的结果,因为for循环中所有的fs.stat执行结束后,data才会获得预期的值。可是,怎么知道for循环全部执行结束了呢?
异常处理
再看看上面的代码,如果多几个需要处理异常的地方,代码可谓支离破碎了。
Promises
Promise是对异步编程的一种抽象。它是一个代理对象,代表一个必须进行异步处理的函数返回的值或抛出的异常。
Promises全称叫Promises/A+,是一个开放的JavaScript规范,已经被加入ES6中。Promises只是一种规范,从Chrome32起开始支持Promises。
已经实现这个标准的库有Q、when.js、Dojo.deferred、jQuery.deferred等。
鉴于浏览器已经支持Promises,所以尽量使用原生的Promises,对于不支持Promises的浏览器,建议使用这个polyfill: promise-5.0.0.js,Promises其实很简单:
function a (num) {var promise = new Promise(function (resolve, reject) {var count = num;if (count >= 10) {setTimeout(function () {count ++;console.log(count);resolve(count);}, 1000);} else {reject(count);}});return promise; } function b (count) {var promise = new Promise(function (resolve, reject) {setTimeout(function () {count *= 10;console.log(count);resolve(count);}, 1000);});return promise; } function c () {console.log('done'); } function alert(num) {console.log('您输入的数字为' + num + ',不能小于10!'); } a(11) .then(b, alert) .then(c);
上面这段代码做的事情是:输入num,1s后输出num + 1,2s后输出(num + 1) * 10,最后输出done。
相比a、b两个方法本身,通过Promises定义的方法多了这些东西:
定义一个promise。
var promise = new Promise(function (resolve, reject) {));
完成方法的功能时,调用resolve(data)。
resolve(count);
最后返回promise。
return promise;
首先熟悉一下Promises是怎样定义promise状态的。Promises/A+是这样规定的:
- 一个promise必须是下面三种状态之一:pending, fulfilled, rejected
- 当一个promise是pending状态:
- 可以转变到fulfilled状态或者rejected状态
- 当一个promise是fulfilled状态:
- 不可以转变到其他任何状态
- 必须有一个不能改变的value
- 当一个promise是rejected状态:
- 不可以转变到其他任何状态
- 必须有一个不可改变的reason
上面代码在a()中使用new Promise()实例化了一个promise后,这个promise默认状态是pending。
promise.then()方法有2个参数,分别是onFulfilled、onRejected,这2个参数都是方法名(也就是回调函数),通过这2个参数可以对应promise的fulfilled和rejected2种状态。
通过上面的代码来解释就是:
当a()正常执行结束时,调用resolve(data)将promise的状态改变为fulfilled,并且通过then()的第一个参数onFulfilled将参数data传递给下一个方法b()。
当a()非正常结束,这里认为a()在执行过程中出现了异常时,调用reject(reason)将promise的状态改变为rejected,并且通过then()的第二个参数onRejected将参数reason传递给下一个方法alert()。
在前面说到流程控制的时候提到的for循环的问题还没有解决:如果想等N个for循环中的回调函数执行结束之后做某些事情,该怎么办?
这时候该用到Promise.all()方法了,比如前面提到的一段代码,需求是这样:
在Node.js中,创建http服务器,读取当前目录下articles目录中的所有文件,遍历所有文件,并根据“目录+文件名”读取文件的最后修改时间,最终返回[{文件名,文件修改时间}, {文件名,文件修改时间}, ...]
这样一个列表到客户端。
这里存在的问题是,读取目录的操作是异步的,for循环读取文件状态的操作也是异步的,而在for循环中的所有异步操作都执行结束后,需要调用response.writeHead()与response.write()将所有异步数据返回到客户端。在使用when.js之前,我能想到的就是把for循环中的异步操作变为同步操作,最后再返回数据,但是就会阻塞其他的同步操作,显然这违背了异步机制。
利用Promise.all()改造过后的代码:
var http = require('http'),fs =require('fs'),connect = require('connect'),Promise = require('promise'); function readDir (path) {return new Promise(function (resolve, reject) {fs.readdir(path, function (err, files) {if (err) {reject(err);} else {resolve({"path": path,"files": files});}});}); } function getFileStats (data) {varfiles = data.files,promiseList = [];for (var i in files) {(function (i) {var promise = new Promise(function (resolve, reject) {fs.stat(data.path + '/' + files[i], function (err, stats) {if (err) {reject(err)} else {var o = {"fileName": files[i].slice(0, -5),"fileTime": stats.mtime.toString().slice(4, 15)};resolve(o);}})});promiseList.push(promise);})(i);}return Promise.all(promiseList); } var app = connect().use(function(req, res) {if (req.url === '/favicon.ico') {return;} else {readDir('articles/fe').then(getFileStats).then(function (o) {res.writeHead(200, {'Content-Type': 'text/html; charset="UTF-8"'});res.write(JSON.stringify(o));res.end();});}}).listen(8080);
浏览器上的结果:
Promise.all(array)需要传入一个promise数组,其中数组中的每一个promise在fulfill时都会执行resolve(data),这里的data就是前面for循环中每一次异步操作中获得的数据。在promise.all()执行过后,会将每次resolve(data)中的data拼成一个数组,通过then()传递给下一个promise。
Promise.race()
Promise.race()为异步任务提供了竞争机制。比如在N个异步任务中,在最快获得结果的任务之后做某些事情,可以使用Promise.race()。
使用Promise.race()同Promise.all()类似,传入的参数都是promise数组,返回promise数组中最早fulfill的promise,或者返回最早reject的promise。
function a () {var promise = new Promise(function (resolve, reject) {setTimeout(function () {resolve('a');}, 1002);});return promise; } function b () {var promise = new Promise(function (resolve, reject) {setTimeout(function () {resolve('b');}, 1001);});return promise; } function c (data) {console.log(data + ' first!'); } Promise.race([a(), b()]).then(c);
执行结果:b first!
转载于:https://www.cnblogs.com/zhaodongyu/p/3933486.html
JavaScript Promises相关推荐
- 初识JavaScript Promises
JavaScript有很多槽点,嵌套回调怕是千夫所指. 很久之前,我一直使用async来处理JavaScript异步编程中的嵌套回调问题.当然我也大概的了解过一些其它旨在解决这些问题的类库,诸如Eve ...
- javascript promises的使用
javascript 使用promises https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promisess ...
- [转]JavaScript/Node.JS 中的 Promises
JavaScript Promises 初体验 Promise 是什么? Promise 对象用来进行延迟(deferred) 和 异步(asynchronous) 计算. 一个 Promise 处于 ...
- JavaScript中的HTTP GET请求?
我需要在JavaScript中执行HTTP GET请求. 最好的方法是什么? 我需要在Mac OS X破折号小部件中执行此操作. #1楼 上面有很多很棒的建议,但不是很可重用,并且经常被DOM废话和其 ...
- javascript闭包_通过邮寄包裹解释JavaScript闭包
javascript闭包 by Kevin Kononenko 凯文·科诺年科(Kevin Kononenko) 通过邮寄包裹解释JavaScript闭包 (JavaScript Closures E ...
- javascript 应用_如何利用JavaScript的功能使您的应用脱机工作
javascript 应用 In today's world, connectivity has made us more mobile than ever which (paradoxically) ...
- javascript测试_了解有关JavaScript承诺的更多信息:25次测试中从零到英雄
javascript测试 by Andrea Koutifaris 由Andrea Koutifaris 了解有关JavaScript承诺的更多信息:25次测试中从零到英雄 (Learn more a ...
- JavaScript进阶之路——认识和使用Promise,重构你的Js代码
2019独角兽企业重金招聘Python工程师标准>>> 一 .初识Promise 1.什么是promise? Promise可能大家都不陌生,因为Promise规范已经出来好一段时 ...
- 程序员必须掌握的 12 个 JavaScript 技能!
本文论述的12个概念,对于 JavaScript 开发者来说都是非常重要的. 作者 | Nick Scialli 译者 | 谭开朗 责编 | 屠敏 出品 | CSDN(ID:CSDNNews) 以下为 ...
最新文章
- redis(一)--简介
- 双端队列【deque】的常见用法
- 分支限界法实现最优装载c++_分支限界法
- Ubuntu14.04安装pip及配置
- 安装包安装服务,点修复出现的错误”Error 1001:指定的服务已存在“ 解决办法...
- linux端口映射_Linux 系统安全与优化配置
- 【P1714】切蛋糕(单调队列)
- Redis和MongoDB通讯协议简介
- 如何从派生类函数调用父类函数?
- 技校毕业是什么学历_技校毕业是什么学历 属于什么文凭
- [小结] flexbox
- python中如何导入图片_python如何导入图片
- 如何快速解决或避免EDI系统磁盘空间不足?
- grubbs准则 matlab_MATLAB-格拉布斯准则(MATLAB-Grubbs-criterion)-M
- 终极玩转Power BI中Drill-down Choropleth 地图
- php后台管理修改密码,重置网站后台管理员密码
- 无盘服务器 显卡,我也来说说网吧配机器该用什么显卡
- Fairy Tail - Main Theme Slow Version guitar (solo)
- Java学习—画图程序项目(2)
- 网上的打印店能打印图书吗?