js promise 详解

2023年2月21日08:56:33

没有promise之前处理异步的方式

在promise产生之前,js 处理异步的方式是使用回调函数,一个回调函数执行完成,进行下一个回调函数。这样会导致层层嵌套,代码不清晰。容易进入回调地狱

promise 简介

promise的状态

promise 有三种状态  pending(进行中),resolved(成功),rejected(失败)

promise的状态是不可逆的

pending--->resolved 

或者

pending--->rejected

promise 的两个回调函数  resolved  rejected

promise 的参数是一个函数,函数里还有两个参数  resolved  rejected

resolved(res) 处理成功的 函数  它传递的参数 会在then方法里输出

rejected(err) 处理失败的函数  它传递的参数 会在 catch方法里输出

let p1 = new Promise((resolved, rejected) => {
  let randomVal = Math.random();
  if (randomVal > 0.5) {
    resolved(randomVal + "成功");
  } else {
    rejected(randomVal + "失败");
  }
})
  .then((res) => {
    console.log(res)//0.6423699367939153成功
  })
  .catch((err) => {
    console.log(err)//0.3423699367939153失败
  });

promise.all  同时执行多个promise

promise.all 的参数是多个promise函数,直到慢的一个promise执行完毕才返回所有的promise的结果,有一个promise函数崩溃,整个promise就崩溃,所以要慎用

let p1 = new Promise((resolved, rejected) => {
  let randomVal = Math.random();
  if (randomVal > 0.1) {
    resolved(randomVal + "成功");
  } else {
    rejected(randomVal + "失败");
  }
})

let p2 = new Promise((resolved, rejected) => {
  let randomVal = Math.random();
  setTimeout(() => {
    if (randomVal > 0.9) {
      resolved("成功" + randomVal);
    } else {
      rejected("失败" + randomVal);
    }
  }, 200);
});

Promise.all([p1,p2]).then(resList=>{
    console.log(resList)
}).catch(err=>{
    console.log("错误err"+err)
}).finally(result=>{
    console.log("无论成功或者失败都会执行",result)
})

promise.race 多个promise 执行速度pk看谁的速度最快,返回最快的promise的结果

let p1 = new Promise((resolved, rejected) => {
  let randomVal = Math.random();
  if (randomVal > 0.1) {
    resolved(randomVal + "成功");
  } else {
    rejected(randomVal + "失败");
  }
})

let p2 = new Promise((resolved, rejected) => {
  let randomVal = Math.random();
  setTimeout(() => {
    if (randomVal > 0.9) {
      resolved("成功" + randomVal);
    } else {
      rejected("失败" + randomVal);
    }
  }, 200);
});

Promise.race([p1,p2]).then(resList=>{
    console.log(resList)
}).catch(err=>{
    console.log("错误err"+err)
}).finally(result=>{
    console.log("无论成功或者失败都会执行",result)
})

什么是宏任务,微任务

常见的 宏任务

setTimeout  setInterval

常见的微任务

Promise.then Promise.catch Promise.finally

MutationObserver

process.nextTIck(nodejs里的)

执行顺序

同一层的 先执行主线层然后执行微任务,最后执行 红任务

几道有意思的promise面试题

场景1 

promise resolved函数执行完毕之后才执行 then的方法


new Promise((resolved,rejected)=>{
    console.log("1")
}).then(res=>{
    console.log("2")
    console.log(res)
})
console.log("4")

错误解法 和错误的思路
错误答案  1,4,2 ,1

错误思路,

一般人想 主线程 同步任务走完,然后走 微任务

实际上 promise里没有走resovled函数的时候是不会走 then里的

同理  promise里没有走rejected函数的时候是不会走 catch里的

所以正确的答案是

1 4 

场景 2 

resovled函数外边包裹了定时器,得定时器计时结束才能 调用resolved,最后走then

new Promise((resolved, rejected) => {
    console.log("1")
  setTimeout(() => {
    resolved("2");
  }, 20);

  console.log("3");
}).then((res) => {
  console.log("4");
  console.log(res);
});
console.log("5");
setTimeout(ele=>{
  console.log("6")
},0)

这题直接上正确答案

1,3,5,6,4,2     

答案解析

1 promise主体函数的代码,是同步主线程的优先执行

3 同1 

5 是主线程

6 和 2 4  res(2) 相比都是定时器里的代码(红任务),只是 6的延时时间较少,所以优先执行6

4 2 是promise 里的resolved走完之后,执行then 里的  4    res是 resolved("2")里返回的2,所以打印出 2

场景3 主线程 宏任务 微任务 综合

console.log("1");
setTimeout(function() {
  console.log("2");
  process.nextTick(function() {
    console.log("3");
  });
  new Promise(function(resolve) {
    console.log("4");
    resolve();
  }).then(function() {
    console.log("5");
  });
});
process.nextTick(function() {
  console.log("6");
});
new Promise(function(resolve) {
  console.log("7");
  resolve();
}).then(function() {
  console.log("8");
});
setTimeout(function() {
  console.log("9");
  process.nextTick(function() {
    console.log("10");
  });
  new Promise(function(resolve) {
    console.log("11");
    resolve();
  }).then(function() {
    console.log("12");
  });
});

答案

  1  7 6 8 2 4 3 5 9 11 10 12

1 主线程

7 promis主体函数里的代码 主线程

6 process.nextTick 微任务

8  promise resolve函数处理过走 then 

2  2345 和 9101112 分别在两个定时器里 由于两个定时器的时间是一致的,所以根据先后i顺序执行,先执行上面的,再执行下边的

2345  2是主线程 

          4是主线程

          3 是微任务

          5是微任务

9101112

           9 是主线程

           11 是主线程        

           10 是微任务

            12 是微任务

总结

        当主线程 红任务 微任务在一起的时候,先执行主线程,然后执行微任务,最后执行红任务

场景4 promise.resolve().then 和 setTimeout(()=>{},0) pk

首先我们了解一下 promise.resolve()是什么的简写

new Promise((resolve)=>{
    resolve()
}).then(res=>{
    console.log("123")
})

那么一下两个哪个更快呢

setTimeout(ele=>{
    console.log("2")
})
Promise.resolve().then(res=>{
    console.log("1")
})

将 Promise.resolve().then 转换成上一个写法可以知道 1 是微任务,2 是宏任务,

所以先走1 再走 2

我们接下来再看一题

setTimeout(ele=>{
    console.log("1")
    Promise.resolve().then(res=>{
        console.log("2")
    })
})
Promise.resolve().then(res=>{
    console.log("3")
    setTimeout(ele=>{
        console.log("4")
    })
})

先走 微任务 3 

然后走 上边定时器里的 

        走主线程 1

        走微任务 2

然后走下边的 宏任务

注意

        当出现定时器时 按照 延迟时间和创建先后顺序 这两个条件 先后执行定时器,并且只有执行完一个定时器之后,才执行下一个定时器

场景5 定时器嵌套

        

setTimeout((ele) => {
  console.log(1);
  setTimeout(() => {
    console.log(2);
  }, 40);
}, 20);
setTimeout((ele) => {
  console.log(3);
}, 30);

这一题

很多人的答案时1 2 3

他们想的是先走完第一个定时器里的再走第二个定时器里的

实际上 第一个嵌套的定时器会产生叠加 

2  的执行时间时 20 + 40 也就是 60

而 3 的时间时30 所以时 1  3  2 

注意当定时器嵌套时 ,里边的执行时间是会和上边的叠加的

以上是我对红任务微任务的一些理解,希望对大家能有所帮助,记得点个赞哦

  • 作者:丰的传说
  • 原文链接:https://blog.csdn.net/qq_42389674/article/details/122060478
    更新时间:2023年2月21日08:56:33 ,共 4311 字。