深入理解JS异步编程-Promise


Posted in Javascript onJune 03, 2019

前言

“JS 是基于单线程事件循环”的概念构建的,回调函数不会立即执行,由事件轮询去检测事件是否执行完毕,当执行完有结果后,将结果放入回调函数的参数中,然后将回调函数添加到事件队列中等待被执行。

同时也讲了回调函数的问题:

一是“回调地狱”,因为异步回调函数的特点:回调函数是作为异步函数的参数,一层一层嵌套,当嵌套过多,将使代码逻辑变得混乱,也无法做好错误捕捉和处理(只能在回调函数内部 try catch)。

二是回调的执行方式不符合自然语言的线性思维方式,不容易被理解。

三是控制反转(控制权在其他人的代码上),假如异步函数是别人提供的库,我们把回调函数传进去,我们并不能知道异步函数在调用回调函数之外做了什么事情。

func1(() => {
func2(() => {
func3(() => {
func4(() => {
try {
...
} catch (err){
...
}
})
});
});
});

一、Promise 原理

首先,Promise 中文翻译为“承诺”, 是 JavaScript 的一种对象,表示承诺终将返回一个结果,无论成功还是失败。
Promise 有三个状态:等待中(pending),完成(fullfilled),失败(rejected), Promise 的设计具有原子性,状态一旦从 pending 状态转换为 fullfilled 状态或者 rejected 状态后,将不能被改变。

深入理解JS异步编程-Promise

var promise1 = new Promise((resolve, reject) => {
console.log("Promise 构造器会立即执行");
setTimeout(function (){
if(true) {
resolve("完成");
} else {
reject("失败");
}
}, 1000);
})
promise1
.then((result) => {
// do something
console.log(result);
return 1
// return Promise.resolve(1); // 返回一个决议为成功的 promise 实例
// return Promise.reject("error"); // 返回一个决议为拒绝的 Promise 实例
})
.then((result) => {
// .then() 方法会返回一个 promise, 完成调用的参数为前一个 promise 的返回值或者决议值。
// do other things
console.log(result);
throw new Error("错误") // 抛出错误是隐式拒绝
})
.catch((error) => {
// 捕捉错误
console.log(error)
})
.then(() => {
// 还能继续执行!
})
.finally(() => {
// always do somethings
console.log("finally!")
})

二、Promise 的优势

1.链式调用

Promise 使用 then 方法后还会返回一个新的 Promise 对象,便于我们传递状态数据,同时链式写法接近于同步写法,更符合线性思维。

2.错误捕捉

相比回调函数的错误无法在外部捕捉的问题,Promise 能够为一连串的异步调用提供错误处理。

3.控制反转再反转

由于第三方提供的异步函数,无法保证回调函数如何被执行,但是 Promise 的特点,能够保证异步函数只能被 resolve 一次,以及始终以异步的形式执行代码。

4.可以利用 Promise.all 和 Promise.race 来解决 Promise 始终未决议和并行 Promise 嵌套的问题

三、Promise 的不足

1.每个 .then() 都是一个独立的作用域

加入有很多个 .then() 方法,就会创建很多个独立的作用域,那么将只能通过外面包裹一层函数作用域的闭包来共享状态数据

2.无法取消单个 .then()

当 Promise 链中任意一个 .then() 方法中有语句执行错误后,尽管经过 catch 方法的错误处理,还是并不会中断整个 Promise 链的执行。

3.无法得知进度

由于 Promise 只能从 pending 到 fullfilled 或 rejected 状态,无法得知 pending 阶段的进度。

四、Promise 应用

// Promise 封装 ajax
function fetch(method, url, data){
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
var method = method || "GET";
var data = data || null;
xhr.open(method, url, true);
xhr.onreadystatechange = function() {
if(xhr.status === 200 && xhr.readyState === 4){
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
xhr.send(data);
})
}
// 使用
fetch("GET", "/some/url.json", null)
.then(result => {
console.log(result);
})
// 封装 nodejs error first 风格回调
function readFile(url) {
return new Promise((resolve, reject) => {
fs.readFile(url,'utf8', (err, data) => {
if(err) {
reject(err);
return;
}
resolve(data)
}) 
})
}

五、总结

Promise 是 ES6 提出的简化异步流程控制新规范,强调异步任务的完成状态且具有原子性,这使得我们的代码更容易追踪和维护。Promise 在事件轮询中属于异步事件队列中的微任务,而微任务总是一次性全部执行,而宏任务是每轮轮询执行一个。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript使用cookie
Feb 02 Javascript
一个tab标签切换效果代码
Mar 27 Javascript
jQuery 打造动态下滑菜单实现说明
Apr 15 Javascript
JavaScript的strict模式与with关键字介绍
Feb 08 Javascript
js加载读取内容及显示与隐藏div示例
Feb 13 Javascript
通过$(this)使用jQuery包装后的方法或属性
May 18 Javascript
jQuery仿写百度百科的目录树
Jan 03 Javascript
纯JS实现图片验证码功能并兼容IE6-8(推荐)
Apr 19 Javascript
pm2 部署 node的三种方法示例
Oct 20 Javascript
vue强制刷新组件的方法示例
Feb 28 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
May 30 Javascript
vue 移动端记录页面浏览位置的方法
Mar 11 Javascript
模块化react-router配置方法详解
Jun 03 #Javascript
react 组件传值的三种方法
Jun 03 #Javascript
angular使用md5,CryptoJS des加密的方法
Jun 03 #Javascript
Node.js 的 GC 机制详解
Jun 03 #Javascript
微信小程序蓝牙连接小票打印机实例代码详解
Jun 03 #Javascript
react-native滑动吸顶效果的实现过程
Jun 03 #Javascript
vue-cli 3 全局过滤器的实例代码详解
Jun 03 #Javascript
You might like
十天学会php之第四天
2006/10/09 PHP
用php和jQuery来实现“顶”和“踩”的投票功能
2016/10/13 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
2017/11/16 PHP
List Information About the Binary Files Used by an Application
2007/06/18 Javascript
jquery 学习之一 对象访问
2010/11/23 Javascript
动态创建script在IE中缓存js文件时导致编码的解决方法
2014/05/04 Javascript
javascript继承机制实例详解
2014/11/20 Javascript
node.js中的http.get方法使用说明
2014/12/14 Javascript
jQuery中:has选择器用法实例
2014/12/30 Javascript
js实现Select下拉框具有输入功能的方法
2015/02/06 Javascript
JavaScript中Date.toSource()方法的使用教程
2015/06/12 Javascript
JS组件Bootstrap ContextMenu右键菜单使用方法
2016/04/17 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
2016/11/29 Javascript
ZeroClipboard.js使用一个flash复制多个文本框
2017/06/19 Javascript
javascript定时器取消定时器及优化方法
2017/07/08 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
对angularJs中2种自定义服务的实例讲解
2018/09/30 Javascript
VUE+Element环境搭建与安装的方法步骤
2019/01/24 Javascript
微信小程序 调用远程接口 给全局数组赋值代码实例
2019/08/13 Javascript
[44:15]国士无双DOTA2 6.82版本详解(上)
2014/09/28 DOTA
[34:39]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第二局
2016/03/05 DOTA
[01:05:52]DOTA2-DPC中国联赛 正赛 Ehome vs Aster BO3 第一场 2月2日
2021/03/11 DOTA
python解析xml文件实例分享
2013/12/04 Python
Python编程中运用闭包时所需要注意的一些地方
2015/05/02 Python
用yum安装MySQLdb模块的步骤方法
2016/12/15 Python
简单了解python关系(比较)运算符
2019/07/08 Python
使用 python pyautogui实现鼠标键盘控制功能
2019/08/04 Python
HTML5 Canvas的常用线条属性值总结
2016/03/17 HTML / CSS
html2canvas把div保存图片高清图的方法示例
2018/03/05 HTML / CSS
Foot Locker澳洲官网:美国运动服和鞋类零售商
2019/10/11 全球购物
优秀应届毕业生自荐书
2014/06/29 职场文书
幼儿教师继续教育培训心得体会
2016/01/19 职场文书
高效课堂教学反思
2016/02/24 职场文书
如何让2019年上半年的工作总结更出色!
2019/07/01 职场文书
演讲稿之感恩老师(三篇范文)
2019/09/06 职场文书
python数据分析之单因素分析线性拟合及地理编码
2022/06/25 Python