交流群:462197261站长百科站长论坛热门标签收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
点击这里给我发消息
  • 当前位置:
  • 深入理解JS异步编程-Promise

    前言

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

    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异步编程的六种方式总结
    • nodejs异步编程基础之回调函数用法分析
    • Javascript实现异步编程的过程
    • 详解JavaScript异步编程中jQuery的promise对象的作用
    • 跟我学习javascript解决异步编程异常方案
    • 异步JavaScript编程中的Promise使用方法
    • 深入理解JavaScript编程中的同步与异步机制
    • 新手如何快速理解js异步编程

    广而告之:
    热门推荐:
    DeDeCms修改责任编辑无效的解决方法

    关于DeDeCms修改责任编辑无效的BUG,在论坛问了多人,都没有解决,后来经过自己研究还是解决了,特别将方法分享给大家,修改文件为include/taglib/adminname.lib.php。     用以下代码替换即可。   以下为引用的内容: <?php if(!defined('DEDE···

    使用node.js对音视频文件加密的实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: fs.readFile('./downsuccess/'+name+'', {flag: 'r+', encoding: ''}, function (err, data) { console.log('读取中') if(err) { return; } let b = new Buffer(···

    JS工作中的小贴士之”闭包“与事件委托的”阻止冒泡“

    说下闭包的由来 function a() { var i = 0; function b() { console.log(i); } return b; } var c = a(); c(); 一般来说,当一个函数内部匿名函数用到了自己的变量,并且这个匿名函数被返回了,这就建立了一个闭包,比如上面的代码 这个时候,就算a调用结束被销毁,i也会存···

    javascript实现轮显新闻标题链接

    用两个div嵌套链接文字,最外面的div设置 overflow:hidden,并用js动态控制它的width,实现伸展与收缩。 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transi···

    js判断一点是否在一个三角形内

    *{margin:0;padding:0;} [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]

    JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什么,有什么用,今天在网上看到了一篇讲JavaScript闭包的文章(原文链接),讲得非常好,这下···

    JQuery CheckBox(复选框)操作方法汇总

    1.   获取单个checkbox选中项(三种写法): 复制代码 代码如下: $("input:checkbox:checked").val() 或者 复制代码 代码如下: $("input:[type='checkbox']:checked").val(); 或者 复制代码 代码如下: $("input:[name='ck']:checked").val(); 2.   获取多个···

    详解Webpack实战之构建 Electron 应用

    Electron 可以让你使用开发 Web 的技术去开发跨平台的桌面端应用,由 Github 主导和开源,大家熟悉的 Atom 和 VSCode 编辑器就是使用 Electron 开发的。 Electron 是 Node.js 和 Chromium 浏览器的结合体,用 Chromium 浏览器显示出的 Web 页面作为应用的 GUI,通过 Node.js 去···

    PHP5.5安装PHPRedis扩展及连接测试方法

    本文实例讲述了PHP5.5安装PHPRedis扩展及连接测试方法。分享给大家供大家参考,具体如下: phpredis是个人觉得最好的一个php-redis客户端,因为其提供的function与redis的命令基本一致,降低的了学习成本,同时功能也很全面。 一、linux安装方法 phpredis下载地址:https://git···

    JavaScript获取table中某一列的值的方法

    1、实现源码 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-···