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
posted @ 2020-11-15 19:06  sk-xm  阅读(65)  评论(0编辑  收藏  举报