Promise学习总结

写在前面:
第一遍学Promise时, 只是大概过了一遍, 感受学的不够深刻, 这一篇算是对以前的一个总结吧. Promise在ES6中也属于一个较难理解的一部分; 因此在学习一个比较难理解的知识点时, 咱们能够围绕这个知识点进行展开,逐个去理解.前端

再探Promise

理解一个知识点, 不妨先列出下面几个问题.ajax

  • Promise是用来干什么的?
  • Promise是什么?
  • Promise如何去建立,使用?
  • Promise的经常使用形式?
  • Promise的使用有哪些注意点?

异步相关背景介绍

浏览器内核

首先聊一下浏览器, 一直对浏览器的结构比较好奇,查了不少资料总结就有下面一点相关总结; 其中也借鉴其余人的一些东西.
浏览器是多进程的,有主进程, GPU加速进程,渲染进程(内核)等, 通常新开一个tab页面就是新启动一个进程, CPU就会给他分配资源; 但其中有一个核心进程==>渲染进程(浏览器内核), 是咱们前端人员须要特别关注的,它包括了多个线程...编程

  • GUI渲染线程promise

    负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
    当界面须要重绘(Repaint)或因为某种操做引起回流(reflow)时,该线程就会执行
    
    注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(至关于被冻结了),
    GUI更新会被保存在一个队列中等到JS引擎空闲时当即被执行。
  • JS引擎线程浏览器

    也称为JS内核,负责处理Javascript脚本程序.(例如V8引擎)JS引擎线程负责解析Javascript脚本,运行代码。
    JS引擎一直等待着任务队列中任务的到来,而后加以处理,一个Tab页(renderer进程)中不管何时都只有一个JS线程在运行JS程序
    一样注意,GUI渲染线程与JS引擎线程是互斥的,因此若是JS执行的时间过长,这样就会形成页面的渲染不连贯,致使页面渲染加载阻塞。
    
    不过H5中新增了Web Worker, 实现了多线程: js会新开线程来处理一些其余任务,但不会影响DOM结构...
    建立Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,彻底受主线程控制,并且不能操做DOM)
    JS引擎线程与worker线程间经过特定的方式通讯
    (postMessage API,须要经过序列化对象来与线程交互特定的数据)
  • 事件触发线程网络

    这个线程是归属于浏览器而不是JS引擎,用来控制事件循环(能够理解,JS引擎本身都忙不过来,须要浏览器另开线程协助)
    当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其余线程,如鼠标点击、AJAX异步请求,
    页面滚动等),会将对应任务添加到事件线程中
    当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
    注意,
    因为JS的单线程关系,因此这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)
  • 定时触发器线程多线程

    即setInterval与setTimeout所在线程
    浏览器定时计数器并非由JavaScript引擎计数的,(由于JavaScript引擎是单线程的, 若是处于阻塞线程状态就会影响记计时的准确); 
    所以经过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
    固然setTimeout中的延时参数也不必定准确
  • 异步HTTP请求线程cors

    在XMLHttpRequest在链接后是经过浏览器新开一个网络线程去请求
    将检测到状态变动时,若是设置有回调函数,异步线程就产生状态变动事件,
    将这个回调再放入事件队列中。再由JavaScript引擎执行。

那么关于浏览器方面的背景知识就介绍到这里啦, 想要深刻去了解,能够去查相关资料...异步

事件队列和循环

你们都知道JavaScript引擎是单线程的工做模式, 即同一时间只能跑一段代码,还要按顺序自上而下执行; 可是碰到I/O操做, 定时器, 事件监听函数等这些耗时操做; JS引擎不会等待它们有结果了才去之下它们后面的代码, 而是会将它们扔进任务(事件)队列中, 等待同步代码执行栈空了以后, 再去任务队列将任务一个个取出来执行任务所对应的回调函数, 执行完毕后会一直等待新的任务到来; 如此循环...异步编程

几个类型的回调

  • 同步回调函数

    咱们能够利用了函数的执行栈顺序,函数做为参数放到另外一个函数中调用, 谁在后面调用谁就先被放在函数执行栈栈顶

  • 异步回调函数

    事先在外面定义好一个callback; 将回调函数做为某个函数的参数, 利用函数的做用域将函数中异步任务获得的结果存在回调函数的形参中, 而后在函数体末尾调用...

  • 定时器
    setTimeout的做用是在间隔必定的时间后,将回调函数插入任务队列中,等栈中的同步任务都执行完毕后,再执行, 固然这个时间不必定准确...

Promise是用来干什么的?

看阮老师的ES6出门上说Promise是JS异步编程的一种解决方案. 举个例子, Ajax的回调问题, 若是下一个ajax请求要用到上一个Ajax请求中的结果, 那么每每就会致使多个回调嵌套的问题, 那么Promise就能够解决这种代码上的嵌套问题, 是咱们的代码变得更优美, 更利于维护; 我暂时先对Promise的理解就是: 处理异步任务, 保存异步结果状态, 异步代码同步化...

Promise是什么?

Promise 它就是一个对象,至关于一个容器, 里面存的就是一个异步操做的结果; 咱们能够是从中获取异步操做结果的相关信息。

Promise对象表明一个未完成、但预计未来会完成的操做。
它有如下三种状态:

pending:初始值,不是fulfilled,也不是rejected
fulfilled:表明操做成功
rejected:表明操做失败

Promise有两种状态改变的方式,既能够从pending转变为fulfilled,也能够从pending转变为rejected。一旦状态改变,就「凝固」了,会一直保持这个状态,不会再发生变化。当状态发生变化,promise.then绑定的函数就会被调用。
注意:Promise一旦新建就会「当即执行」(它属于microtask),没法取消。这也是它的缺点之一。

Promise的建立和使用?

1.建立promise对象

//1.使用new Promise(func)的形式
//2.快捷语法: Promise.resolve(func) || Promise.reject(func)
// 参数1: 通常是一个处理异步任务的函数  
// 返回值: 一个promise实例对象
Promise.resolve('foo')
// 等价于, 不过参数类型不同执行的操做也会有所不一样
new Promise(resolve => resolve('foo'))

2.在函数func中 放异步处理代码

// 传入两个参数: 回调函数resolve, reject分别去保存异步处理的结果
// 成功: 使用resolve(结果)
// 失败: 使用reject(缘由)

3.调用实例的then(func1) 或者 catch(err)

首先then方法是异步执行, 对上面的异步结果进行处理的函数
参数: 传回调函数, 一个两个都行, 前者是成功状态的回调,后者是失败的回调

Promise经常使用的场景?

  • promise通常的使用套路就是:

    1.先定义一个函数, 函数内部使用new Promise()的方式来返回一个promise对象, resolve用来保存 异步处理成功的结果
    reject用来保存 异常处理的结果
    2.而后函数调用,传参
    3.链式语法点出then方法, then中的回调用来处理异步结果
    4.有错误就点出catch方法, 也能够用then(null, function() {})代替catch
    5.then的回调中也可return一个值, 会被包装成一个新的promise, 所以能够继续调用then方法
  • 应用场景: 在ajax中使用, 解决异步嵌套问题

function ajax(url) {

        return new Promise((resolve, reject) => {
    
            let xhr = new XMLHttpRequest();
            // 请求类型, 地址, 异步
            xhr.open('get', url, true);
            xhr.send();
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    try {
                        // 处理响应内容, 将内容丢到成功状态的回调
                        resolve(JSON.parse(xhr.responseText))
                    } catch (e) {
                        // 捕获错误, 丢到失败状态的回调
                        reject(e)
                    }
                }
            }
        });
    }

    // 调用 封装的ajax函数
    let url = 'http://127.0.0.1:3000/xxoo'; // 本身本地开的一个服务

    ajax(url)
        .then(res => console.log(res)) // 输出 {code: 0, msg: 'hello cors'}
        .catch(err => console.log(err))

```
  • 其余场景

    // 实现串行任务管道; 即当前任务的输出能够做为下一个任务的输入,造成一条数据管道;
        // 好比: 好比从url1获取参数userId,拿到后再从url2获取第三方openId,最后再从url3货取orderList,
        而后把结果展现给用户,相似的逻辑都是任务管道:
        
        new Promise(function(resolve, reject) {
            resolve(1);
        })
        .then(function(res) {
            return new Promise(function(resolve, reject) {
                resolve(res + 1);
            });
        })
        .then(function(res) {
            return new Promise(function(resolve, reject) {
                resolve(res + 1);
            });
        })
            .then(function(res) {
            console.log(res); // 3
        });

promise的好处

  • 在异步执行的流程中,使用Promise能够把 执行代码 和 处理结果 的代码清晰地分离
    这样咱们即可以 把执行代码 和 结果处理 分红不一样的模块来写,易于维护

  • 减小异步回调的嵌套, 好比ajax回调, 咱们能够依次调用then方法便可, 还能够控制回调的顺序
  • 多个异步任务是为了容错去访问用同一资源时, 可使用Promise.race([promise实例...])
  • 多个异步任务并行执行时,好比ajax访问两个接口, 能够用Promise.all([promise实例...])

Promise使用的注意事项

  1. Promise构造函数内的同步代码当即执行
  2. 回调函数参数resolve异步执行, 将结果做为参数传给then方法中的回调函数
  3. resolve只有第一次执行有效,状态不能二次改变
  4. then和catch若是有return, 返回的是一个全新的promise对象, 能够链式调用
  5. Promise构造函数只会执行一次, promise实例会保存resolve的状态,
    之后这个实例每次调用then都是返回一个这个状态, 若链式调用then,下一个则会打印undefined, res没有值...
  6. then中返回任意一个非 promise 的值都会被包裹成 promise 对象
  7. .then 或 .catch 返回的值不能是 promise 自己,不然会形成死循环
  8. .then 或者 .catch 的参数指望是函数,传入非函数则会发生值穿透。
  9. .then 能够接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。.catch 是 .then 第二个参数的简便写法,可是它们用法上有一点须要注意:.then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,然后续的 .catch 能够捕获以前的错误。
相关文章
相关标签/搜索