ES6中的Promise
ES6中的Promise
JavaScript本身是单线程语言,这在Node.js学习中已经反复强调过,因为单线程,就需要在程序进行IO操作时做“异步执行”,比如最典型的网络操作——ajax的使用。
在ajax请求网络时,就是在异步执行这个过程,等到异步工作执行完成,通过事先注册好的回调函数,异步事件完成立即触发回调函数,将回调函数拉入到同步执行中。
可见,异步操作会在将来的某个时间点触发一个事件来调用某个函数(callback)。
传统异步与回调函数
在ES5的时代,使用回调函数,在异步代码执行完后,拉回“正轨”(同步到主线程中),例如以下的jquery ajax例子:
$.post("/example/jquery/demo_test_post.asp",{name:"Donald Duck",city:"Duckburg"},function(data,status){alert("数据:" + data + "\n状态:" + status);});
这段js代码做了一个post请求,并注册了请求结束后的回调函数,而这样写代码最大的两个问题是:1、不美观,2、回调函数不好重复使用。
特别是在有多个异步操作且互相约束的情况下,就需要在回调函数中继续使用回调函数,导致callback地狱,写出一堆括号嵌套的代码出来。
试试Promise
Promise是ES6新增的标准,在ES5时代,已经有一些黑科技自己去模拟出这个Promise实现。
什么是Promise?
正如其翻译过来的字面意思“承诺”,Promise是代码和代码,函数和函数之间的承诺。
来看个简单的Node.js数据库连接栗子:
1、使用Promise建立一个公用连接池
const mysql = require("mysql")
const conn_info={host:"localhost",user:"root",password:"",database:"cslginfo"
}function query(sql){let pool = mysql.createPool(conn_info);return new Promise(function(resolve,reject){pool.getConnection(function(err,conn){if(err)reject("error connecting:"+err.stack);else{conn.query(sql,function(err,res,fields){if(err){reject("error query");}else{resolve(res);}});}})})
}
这里使用Promise为异步操作结束后提供一个承诺的函数,意思是异步函数结束时你必须给个结果,要么获得了数据,要么中间出了错误,给出错误信息
使用resolve表示成功的连接了,使用reject来给出错误,这种感觉有点像一个函数可以有多个返回。
resolve将会触发链式操作的then,并将结果注入到函数变量参数中
reject将会触发链式操作的catch,并将结果注入到函数变量参数中
2、连接池的简单使用
const sql="select * from student_base_info limit 10";
query(sql).then(function(results){//resolve给出的承诺在then中兑现console.log(results)
}).catch(function(err){//reject给出的承诺兑现在catch中console.log(err)
})
3、更高级!多表查询!
上面那种情况并不能体现出Promise的特色,只不过是在then中传入一个function罢了,这和传统的回调大法传入function没有区别呀!
那假设这种场景:我们查询学校某个学生的基本信息后,有另一张表对应了学生多条学历经历,我们查询某个学生的学历经历就是一种多表之间的依赖查询,第二次查询学历经历需要根据第一次查询学生的ID。如果还是使用传统的回调函数就会出现:回调函数中嵌套着下一层回调函数,这是为了等待当前查询结束触发下一次查询导致的,下一次查询的函数必须放在当次查询的函数里面。如果关联的表较多,代码写出来就会相当难看,基本就是这种鸟样子:
query("select * form xxx where xxx=xxx",function(results){query("select * from xxx where ID="results[0].id,function(){......query("sql",function(){query("sql",function(){......})})})
})
//每一次query查询都依赖上一次查询的结果,这就很难受了
但Promise的then.then.then链式查询可以将这么多查询串成一个“烤串串”,而不必层层嵌套
//多表关联查询
query(`select * from student_base_info where 姓名 = '黄有为'`).then(res=>{return query(`select * from student_school_info where 学号 = '${res[0].学号}'`)
}).then(res=>{console.log(res);
}).catch(err=>{console.log(err);
});
像这样的链式代码就显得十分优雅舒适了,就好像一个个诺言在一个个往下实现,用专业的术语说就是:Promise的then把异步操作同步化了。
上述js代码所做的工作是,查询一个名叫“黄有为”的人,并从另一张表中根据他的学号查出他上学的经历,最终效果如下所示:
4、别干傻事!
千万千万要注意,不要在then中再嵌套then,这就没有意义了,还不如写你的“回调地狱”去!
不要写出这种代码来:
关于Promise一些坑
在使用Promise对象时,还需要注意一些坑!笔者在使用时遇到了不少坑!
1、同一个Promise不能多次使用!
例如:
let num = 0;
let p = new Promise(function(resolve){resolve(num);
})while(num<10){p.then(res=>{console.log(res);});num++;
}
p是同一个Promise对象,其中代码只会执行一次,故执行后:
我们发现resolve所给出的res结果没有变过,说明之后9次都会输出第1次的res结果,承诺已经兑现,不再执行!结论:同一个Promise对象只兑现一次“承诺”。
解决方案:Promise工厂函数
对上面代码稍作修改:
let num = 0;
let p = function(num){return new Promise(function(resolve){resolve(num)});
}while(num<10){p(num).then(res=>{console.log(res);});num++;
}
控制台输出:
工厂模式除了能解决多个Promise的问题,还为Promise执行提供输入参数。
2、多个resolve,reject只传值一次,后面代码依然要执行?
当多个resolve,reject混合出现在一个逻辑当中,执行到第一个resolve或reject就会返回到then的函数中。但是!注意但是!!!这些resolve,reject之后的代码依然会执行!也就是说resolve,reject不能看成是return或者throw操作,他返回一些变量但是却不结束代码段。做几个测试,修改1中一些代码:
return new Promise(function(resolve,reject){resolve("same");resolve(num);reject("error");throw(new Error("ss"))console.log("test");})
上述代码中test不会打印,因为throw结束了函数,换成return也是一样的效果,而then实际接收到的变量应该是“same”,后面的resolve并不会覆盖第一个,reject也不会覆盖,但是他们都是会执行的!
效果:
如下代码:
return new Promise(function(resolve,reject){resolve("same");resolve(num);reject("error");console.log("test");})
其中的console.log()就是要执行的,效果:
最后,一个小疑问。如果是多层的多对多数据库查询呢?
想象下这种场景,我从表1中读取了10条数据,再依据这10条,每条从表2中读取相关的10条(最后应该是100条),问题不在于最后到底几条数据,而在于读完第一个10条之后不知道如何通过链式查询读与这10条相关的100条数据,因为这种查询是一个树状查询,但Promise的then是种链式查询,无论是逻辑上还是物理上都不好通过Promise和then来实现这种查询,当然你可以通过工厂模式在第一次查询出10条数据(乃至n条)后生产n个Promise对象继续往下模拟出树状查询,但这实现起来很麻烦,并且很难管理这么多的Promise。
最好的办法是通过ES7中的async和await来完成异步化同步的转变!
async,await下一章再说,累了,休息了,祝自己生日快乐!
ES6中的Promise相关推荐
- 【JavaScript 教程】ES6 中的 Promise对象 详解
[JavaScript 教程]ES6 中的 Promise对象 详解 1.Promise对象含义 promise是异步编程的一种解决方法. 所谓promise,简单说是一个容器,里面保存着某个未来才会 ...
- ES6中的Promise使用方法与总结
在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的. 但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回 ...
- Promise使用详解2(ES6中的Promise)
2015年6月, ES2015 (即 ECMAScript 6 . ES6 ) 正式发布.其中 Promise 被列为正式规范,成为 ES6 中最重要的特性之一. 1,then()方法 简 ...
- ES6中的Promise详解
Promise 在 JavaScript 中很早就有各种的开源实现,ES6 将其纳入了官方标准,提供了原生 api 支持,使用更加便捷. 定义 Promise 是一个对象,它用来标识 JavaScri ...
- promise ajax 队列,ES6中的promise,从使用promise封装ajax说起
1为啥要用promise? js是单线程的,理论上所有代码都是同步的,从上到下一行行执行.然而就这样傻傻解析运行js的话,碰到较重的任务时,会阻塞进程,如发送一个用户是否登录验证请求,请求完成响应之前 ...
- ES6中的promise、async、await用法详解
<!DOCTYPE html> <html> <head><title>Promise.async.await</title> </h ...
- es6中的promise解读
目录 什么是promise? promise的优点 回调地狱问题 Promise的三种状态 一个简单的promise promise中的then 利用promise解决回调地狱 promise的链式调 ...
- 大白话讲解Promise(三)搞懂jquery中的Promise
前两篇我们讲了ES6中的Promise以及Promise/A+规范,在Promise的知识体系中,jquery当然是必不可少的一环,所以本篇就来讲讲jquery中的Promise,也就是我们所知道的D ...
- 浅析JaveScript中的Promise对象 暮雨清秋
前言 本文旨在简单讲解一下javascript中的Promise对象的概念,特性与简单的使用方法.并在文末会附上一份符合PromiseA+规范的Promise对象的完整实现. 注:本文中的相关概念均基 ...
最新文章
- 技术图文:Numpy 一维数组 VS. Pandas Series
- 解决eclipse修改后台代码ctrl+s总是【自动重启服务器】问题
- asp.net c#截取指定字符串函数
- python怎么创建函数_如何在python中创建自己的map()函数
- 十个摸鱼,哦,不对,是炫酷(可以玩一整天)的网站!!!
- 博弈论——拍卖会(Auctions)
- python 模拟鼠标键盘_如何用 python 模拟鼠标和键盘的操作
- 胖客户端、瘦客户端与智能客户端
- Windows 使用学习
- 数据结构与算法基本概念
- 用于高速网络的实时且可靠的基于异常的入侵检测
- 【论文笔记】UBR4CTR:User Behavior Retrieval for Click-Through Rate Prediction (SIGIR 20)
- 《电机学》第三篇 第10、11、12章 交流旋转电机的共同问题
- 自动化失败的6种原因
- android微信群聊功能,Android仿微信群聊头像效果
- 高效工作学习法——番茄工作法读后感
- 【来灌灌水】~~感谢csdn平台给予新手学习的地方
- launch 文件中remap标签的使用
- ccdebug io引脚_CC2530通用IO口的输入输出
- 天地图解析(瓦片层级、比例尺、行列号计算)
热门文章
- 妈妈!我再也不要参加数学建模大赛了!
- Cadence Capture CIS软件设置与新建原理图图文教程及视频演示
- c语言函数原型语句,C语言函数声明以及函数原型
- mysql 类型_MySQL数据类型
- 今天面试招了个18K的人,从腾讯出来的果然都有两把刷子···
- python制作购物网站开题报告_网上购物网站的开题报告
- JS 最新数据基本类型:BigInt
- 如何把手变成手控_【图片】【转教程】神马手控,转自魔轰神吧【游戏王报社吧】_百度贴吧...
- LabVIEW使用移位寄存器计算平均值
- 醉鹅舜达餐饮才是总部