深入理解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 相关文章推荐
不间断滚动JS打包类,基本可以实现所有的滚动效果,太强了
Dec 08 Javascript
node.js chat程序如何实现Ajax long-polling长链接刷新模式
Mar 13 Javascript
js封装可使用的构造函数继承用法分析
Jan 28 Javascript
JS实现仿苹果底部任务栏菜单效果代码
Aug 28 Javascript
js 自带的 map() 方法全面了解
Aug 16 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
Jan 20 Javascript
js实现一键复制功能
Mar 16 Javascript
ionic+AngularJs实现获取验证码倒计时按钮
Apr 22 Javascript
Javascript快速实现浏览器系统通知
Aug 26 Javascript
vue-router配合ElementUI实现导航的实例
Feb 11 Javascript
JS开发自己的类库实例分析
Aug 28 Javascript
vue3引入highlight.js进行代码高亮的方法实例
Apr 08 Vue.js
模块化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
phpmyadmin中配置文件现在需要绝密的短语密码的解决方法
2007/02/11 PHP
深入extjs与php参数交互的详解
2013/06/25 PHP
PHP获取中英混合字符串长度的方法
2014/06/07 PHP
Zend Framework基本页面布局分析
2016/03/19 PHP
Yii2增加验证码步骤详解
2016/04/25 PHP
thinkphp3.2嵌入百度编辑器ueditor的实例代码
2017/07/13 PHP
基于win2003虚拟机中apache服务器的访问
2017/08/01 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
JS获取scrollHeight问题想到的标准问题
2007/05/27 Javascript
文本框根据输入内容自适应高度的代码
2011/10/24 Javascript
location.href用法总结(最主要的)
2013/12/27 Javascript
jquery使用$(element).is()来判断获取的tagName
2014/08/24 Javascript
Javascript动态创建div的方法
2015/02/09 Javascript
jQuery Validate验证框架经典大全
2015/09/23 Javascript
js实现把图片的绝对路径转为base64字符串、blob对象再上传
2016/12/29 Javascript
javascript使用递归算法求两个数字组合功能示例
2017/01/03 Javascript
详解webpack4升级指南以及从webpack3.x迁移
2018/06/12 Javascript
JavaScript使用享元模式实现文件上传优化操作示例
2018/08/07 Javascript
解决vue的过渡动画无法正常实现问题
2019/10/31 Javascript
Vue检测屏幕变化来改变不同的charts样式实例
2020/10/26 Javascript
javascript局部自定义鼠标右键菜单
2020/12/08 Javascript
[47:45]Liquid vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python实现扫描ip地址的小程序
2019/04/16 Python
Pandas的read_csv函数参数分析详解
2019/07/02 Python
Python for循环与getitem的关系详解
2020/01/02 Python
pytorch自定义二值化网络层方式
2020/01/07 Python
django 取消csrf限制的实例
2020/03/13 Python
什么是python的id函数
2020/06/11 Python
Elemis美国官网:英国的第一豪华护肤品牌
2018/03/15 全球购物
世界上第一个创建了罩杯系统的美国内衣品牌:Maidenform
2019/03/23 全球购物
Camille Jewelry官网:现代女性时尚首饰
2019/07/07 全球购物
幼儿园中秋节活动方案
2014/02/06 职场文书
房产销售员2015年终工作总结
2015/10/22 职场文书
《七律·长征》教学反思
2016/02/16 职场文书
【TED出品】天梯非主流开心游1700 划水骑士
2022/03/31 魔兽争霸
如何使用注解方式实现 Redis 分布式锁
2022/07/23 Redis