博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS异步编程之Promise
阅读量:7119 次
发布时间:2019-06-28

本文共 3150 字,大约阅读时间需要 10 分钟。

前言

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

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

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

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

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

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

一、Promise 原理

首先,Promise 中文翻译为“承诺”, 是 JavaScript 的一种对象,表示承诺终将返回一个结果,无论成功还是失败。

Promise 有三个状态:等待中(pending),完成(fullfilled),失败(rejected), Promise 的设计具有原子性,状态一旦从 pending 状态转换为 fullfilled 状态或者 rejected 状态后,将不能被改变。

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 对象,便于我们传递状态数据,同时链式写法接近于同步写法,更符合线性思维。

  1. 错误捕捉

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

  1. 控制反转再反转

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

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

三、Promise 的不足

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

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

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

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

  1. 无法得知进度

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

四、Promise 应用

// Promise 封装 ajaxfunction 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 在事件轮询中属于异步事件队列中的微任务,而微任务总是一次性全部执行,而宏任务是每轮轮询执行一个,此节内容参考我之前的文章《JS专题之事件循环》。

2019/02/24 @Manncoffee

欢迎关注我的个人公众号“谢南波”,专注分享原创文章。

转载地址:http://iriel.baihongyu.com/

你可能感兴趣的文章
自旋锁的选择
查看>>
MySQL : ERROR 1042 (HY000): Can't get hostname for your address
查看>>
nyoj------擅长排列的小明
查看>>
三大UML建模工具Visio、Rational Rose、PowerDesign的区别
查看>>
全方位讲解硬件防火墙的选择
查看>>
nginx log 错误502 upstream sent too big header while reading response header from upstream
查看>>
静态资源打包:一个javescript 的src引用多个文件,一个link引用多个CSS文件
查看>>
iOS: 在键盘之上显示一个 View
查看>>
[翻译]:SQL死锁-阻塞探测
查看>>
织梦(Dedecms) V5.6 plus/carbuyaction.php 本地文件包含漏洞
查看>>
关于JqueryEasyUI集合Kindeditor
查看>>
漫说中介者模式--创业公司成长记
查看>>
Linked List Cycle
查看>>
[物理学与PDEs]第3章第2节 磁流体力学方程组 2.4 不可压情形的磁流体力学方程组...
查看>>
举例理解Hibernate的三种状态
查看>>
利用yacc和lex制作一个小的计算器
查看>>
Linux命令学习总结:rmdir
查看>>
Socket网络编程--聊天程序(7)
查看>>
TextView中文文档
查看>>
【delphi】delphi出现‘尚未调用CoInitialize’异常
查看>>