深入理解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 相关文章推荐
打开超链需要“确认”对话框的方法
Mar 08 Javascript
基于jQuery的烟花效果(运动相关)点击屏幕出烟花
Jun 14 Javascript
jQuery操作select的实例代码
Jun 14 Javascript
js中opener与parent的区别详细解析
Jan 14 Javascript
jQuery使用getJSON方法获取json数据完整示例
Sep 13 Javascript
网页挂马方式整理及详细介绍
Nov 03 Javascript
Vue Cli与BootStrap结合实现表格分页功能
Aug 18 Javascript
jQuery实现用户信息表格的添加和删除功能
Sep 12 jQuery
Vue表单及表单绑定方法
Sep 04 Javascript
使用VScode 插件debugger for chrome 调试react源码的方法
Sep 13 Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
Nov 09 Javascript
jQuery class属性操作addClass()与removeClass()、hasClass()、toggleClass()
Mar 31 jQuery
模块化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木马webshell扫描器代码
2012/01/25 PHP
计算php页面运行时间的函数介绍
2013/07/01 PHP
php中HTTP_REFERER函数用法实例
2014/11/21 PHP
PHP实现的XXTEA加密解密算法示例
2018/08/28 PHP
javascript当onmousedown、onmouseup、onclick同时应用于同一个标签节点Element
2010/01/05 Javascript
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
2010/04/15 Javascript
javascript中的取反再取反~~没有意义
2014/04/06 Javascript
一个简单的jQuery计算器实现了连续计算功能
2014/07/21 Javascript
jQuery判断浏览器并动态调整select宽度的方法
2016/03/02 Javascript
jQuery flip插件实现的翻牌效果示例【附demo源码下载】
2016/09/20 Javascript
怎样判断jQuery当前元素是隐藏还是显示
2016/11/23 Javascript
JS正则表达式判断有效数实例代码
2017/03/13 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
JS分页的实现(同步与异步)
2017/09/16 Javascript
AngularJs的UI组件ui-Bootstrap之Tooltip和Popover
2018/07/13 Javascript
详解在微信小程序的JS脚本中使用Promise来优化函数处理
2019/03/06 Javascript
小程序中this.setData的使用和注意事项
2019/08/28 Javascript
解决layUI的页面显示不全的问题
2019/09/20 Javascript
用Python编写一个国际象棋AI程序
2014/11/28 Python
python获取本机外网ip的方法
2015/04/15 Python
python fabric使用笔记
2015/05/09 Python
python遍历文件夹下所有excel文件
2018/01/03 Python
谈谈python中GUI的选择
2018/03/01 Python
django admin.py 外键,反向查询的实例
2019/07/26 Python
基于YUV 数据格式详解及python实现方式
2019/12/09 Python
python 成功引入包但无法正常调用的解决
2020/03/09 Python
python如何变换环境
2020/07/21 Python
HTML5中的Scoped属性使用实例
2014/04/23 HTML / CSS
HTML5操作WebSQL数据库的实例代码
2017/08/26 HTML / CSS
canvas 基础之图像处理的使用
2020/04/10 HTML / CSS
Bluebella美国官网:英国性感内衣品牌
2018/10/04 全球购物
linux比较文件内容的命令是什么
2013/03/04 面试题
毕业生求职信
2014/06/10 职场文书
服务行业口号
2014/06/11 职场文书
员工生日活动方案
2014/08/24 职场文书
JavaScript中10个Reduce常用场景技巧
2022/06/21 Javascript