• promise


    promise

    1,Promise是ES6中的新的异步语法,解决了回调嵌套的问题:

    new Promise((resolve)=>{
      setTimeout(()=>{
        resolve(1)
      },1000)
    }).then(val =>{
      console.log(val);  //1s后打印1,由resolve传过来
      return new Promise((resolve)=>{  //里面可以嵌式promise
        setTimeout(()=>{
          resolve(2)
        },1000)
      })
      // return 2  //也可以直接return一个值出去,不用等待
    }).then(val => {
      console.log(val);  //按顺序打印1,2
    })
    

    2,状态切换

    • promise实例有三个状态,
      pending,fulfilled,rejected // 初始状态 // 成功状态 // 失败状态
    • promise实例在构造是可以传入执行函数,执行函数有两个形参resolve,reject可以改变promise的状态,promise的状态一旦改变后不可再进行改变。
    • 执行函数会在创建promise实例时,同步执行

    3,then异步执行

    promise实例可以调用then方法并且传入回调:
    如果调用then时,Promise实例是fulfilled状态,则马上异步执行传入的回调。
    如果调用then时,Promise实例是pending状态,传入的回调会等到resolve后再异步执行

    例子:

    let p = new Promise((resolve, reject)=>{
      console.log(1);
      resolve(2)
      console.log(3);
    })
    p.then((val)=>{  //`fulfilled`状态,因为异步会慢一点
      console.log(val);
    })
    //1 3 2
    
    let p = new Promise((resolve, reject)=>{
      setTimeout(()=>{
        resolve(1)
      },2000)
    })
    p.then((val)=>{
      console.log(val);  //`pending`状态,2s后执行
    })
    

    思路:需要用回调先保存到队列中,在resolve后异步执行队列里的回调,在then时判断实例的状态再决定是将回调推入队列,还是直接异步执行回调:

    4,resolve Promise实例的情况

    resolve的值有可能也是个promise实例,这时候就要用前述实例自己resolve的值

    let p = new Promise((resolve,reject) =>{  //promise1
      resolve(new Promise((resolve2,reject2)=>{  //promise2
        setTimeout(()=>{
          resolve2(1)
        },1000)
      }))
    })
    p.then((val)=>{
      console.log(val);
    })
    

    因此需要在promise1的resolve函数中进行判断,是promise实例则在这个promise实例(promise2)后接一个then,并且将promise1的resolve作为回调传入promise2的then

    5,实现链式调用

    then可以链式调用,而且前一个then的回调的返回值,如果不是promise实例,则下一个then回调的传参值就是上一个then回调的返回值,如果是promise实例,则下一个then回调的传参值,是上一个then回调返回的promise实例的解决值(value)

    let p = new Promise((resolve,reject) =>{
        setTimeout(()=>{
          resolve(1)
        },1000)
    })
    p.then(val => {   //这里.then返回的是一个新的promise实例
      console.log(val);
      return new Promise((resolve) => {
        setTimeout(()=>{
          resolve(2)
        },1000)
      })
    }).then(val => {
      console.log(val);
      return 3
    }).then(val => {
      console.log(val);  //依次打印1,2,3
    })
    

    既然能够链式调用,那么then方法本身的返回值必定是一个Promise实例。那么返回的promise实例是不是自身呢?答案显而易见:不是。如果一个promise的then方法的返回值是promise自身,在new一个Promise时,调用了resolve方法,因为promise的状态一旦更改便不能再次更改,那么下面的所有then便只能执行成功的回调,无法进行错误处理,这显然并不符合promise的规范和设计promise的初衷。
    因此 then方法会返回一个新的promise实例

    6,其他方法

    • catch
    • resolve
    • reject
    • all
    • race

    方法演示:

    /*catch方法*/
    let p = new Promise((resolve, reject) => {
      reject(1)
    })
    p.catch(reason => {  //一个语法糖,捕获错误,对应then
      console.log(reason);
    })
    
    /*Promise.resolve*/
    let p = Promise.resolve(1)  //返回一个新的已解决的promise实例
    
    /*Promise.reject*/
    let p = Promise.reject(1)  //返回一个新的已拒绝的promise实例
    
    /*Promise.all*/
    let p = Promise.all([
      new Promise(resolve => {
        setTimeout(() => {
          resolve(1)
        }, 1000)
      }),
      new Promise(resolve => {
        setTimeout(() => {
          resolve(2)
        }, 2000)
      }),
      new Promise(resolve => {
        setTimeout(() => {
          resolve(3)
        }, 3000)
      }),
    ])
    p.then(val => {  //会等到所有promise都解决后才执行.then,等待3s后返回一个数组[1,2,3]
      console.log(val);
    })
    /*Promise.race*/
    let p = Promise.race([
      new Promise(resolve => {
        setTimeout(() => {
          resolve(1)
        }, 1000)
      }),
      new Promise(resolve => {
        setTimeout(() => {
          resolve(2)
        }, 2000)
      }),
      new Promise(resolve => {
        setTimeout(() => {
          resolve(3)
        }, 3000)
      }),
    ])
    p.then(val => {  //以最早完成为准,等待1s后返回解决的1
      console.log(val);
    })
    

    7,macrotask和mirotask

    所谓macroTask(宏任务)是指将任务排到下一个事件循环,microTask(微任务)是指将任务排到当前事件循环的队尾,执行时机会被宏任务更早。Promise的标准里没有规定Promise里的异步该使用哪种,但在node和浏览器的实现里都是使用的miroTask(微任务)

    setTimeout(() => {  //属于宏任务
      console.log(1);
    }, 0)
    let p = Promise.resolve(2)   //如果这里是Promise2,则打印顺序是1,2
    p.then((val) => {   //这里立即解决了属于微任务  打印顺序是2,1
      console.log(val);
    })
    

    宏任务api包括:setTimeout,setInterval,setImmediate(Node),requestAnimationFrame(浏览器),各种IO操作,网络请求

    微任务api包括:process.nextTick(Node),MutationObserver(浏览器)

    MutaionObserver演示:

    let observer = new MutationObserver(()=>{
      console.log(1);
    })
    let node = document.createElement('div')
    observer.observe(node, { // 监听节点
      childList: true // 一旦改变则触发回调函数 nextTickHandler
    })
    node.innerHTML = 1
    
  • 相关阅读:
    SQL之CASE WHEN用法详解
    MySQL笔记汇总
    Linux常用命令
    TCP/IP速记
    数据结构和算法速记
    多线程相关概念
    线程安全&Java内存模型
    线程通讯wait&notify
    创建多线程的4种方式
    重写ThreadPoolTaskExecutor
  • 原文地址:https://www.cnblogs.com/xm0328/p/13977858.html
Copyright © 2020-2023  润新知