这一次 彻底学会 Promise的基本使用


image.png

文章摘要

本片文章包含以下几个要点:

  • JS(JavaScript )语言的执行机制?
  • 什么是同步任务,什么是异步任务?
  • 传统的回调函数嵌套,造成回调地狱如何解决?
  • Promise的基本使用和原理?
  • Promise 的代码执行机制?
  • Async 和 await 的使用。

1 : JavaScript 执行机制

JavaScript 是一门单线程脚本语言 , 由于Dom 的产生页面无法执行多线程,JavaScript 语言 由上到下有序进行执行
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?   所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。   为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

2: 什么是同步任务,什么是异步任务?

异步任务

异步任务:当JS发现异步任务存在时时,JavaScript 会提交给对应的异步进行处理程序(提交给浏览器)进行处理,当异步任务处理完成的的时候,JS会将该任务加入到异步任务队列中,进行排队,此时JS主线程会一直查询异步消息队列中是否有任务,如果有则 拿到主线程(执行栈)中执行。

常见的异步任务 :

  • settimeout(()=>{}.1000) setinterval(()=>{},1000) 定时器

  • 执行的事件 onclick onchange onload 等…

  • ajax中的onload

  • .then (异步回调)

  • process.nextTick(callback[, …args])

同步任务 :

同步任务: 赋值操作,for 循环 if 分支 运算,等,JavaScript 基础代码执行的为同步任务, JS同步任务会加入到主线程(执行栈)中进行排队执行。

什么是回调地狱 ?

名词解释 :在回调函数中继续嵌套回调函数,造成结构模糊

功能需求 : 实现 三个文件依次读取文件内容

实现思路 : 当第一个文件读取成功时进行第二个文件读取,以此类推

产品经理 吐槽: 结构不清晰,不简单明了,垃圾代码,不会封装函数吗??

// -------异步嵌套----------------------------------------
fs.readFile("./files/1.txt",'utf-8',(err,dataStr)=>{

    if(err) return console.log(err.message);
    console.log(dataStr);

    fs.readFile("./files/2.txt",'utf-8',(err,dataStr)=>{

        if(err) return console.log(err.message);
        console.log(dataStr);

        fs.readFile("./files/3.txt",'utf-8',(err,dataStr)=>{
            if(err) return console.log(err.message);
            console.log(dataStr);
        })

    })
})//** 什么 xxx 玩意 你来  **

使用 Promise 实现

回调变少了但是 .then 好像变多了


import fs from 'fs'
// 主函数 
const ReadFile = (path) => {
  return new Promise((resolve, reject) => {
  // 成功的 调用  resolve  
  // 失败的调用  reject
    fs.readFile(path, 'utf-8', (err, data) => {
      if (err) return reject(err)
      resolve(data)
    })
  })
}


ReadFile("../File/1.txt").then(res => {
  console.log(res);
  // 当走到.then 中 代表执行成功  继续调用读取第二个文件
  return ReadFile("../File/2.txt")
}).then(res => {
  console.log(res);
  return ReadFile("../File/3.txt")
}).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err.message);
})

接下来就是

Promise的基本使用和原理

先介绍 Promise 的三种状态 !

pending (进行中) ,promise对象没有被resolve或者reject 时状态是 pending

const p1 = new Promise((resolve, reject) => { }) // 此状态为 pending

Fulfilled (成功状态)

const p1 = new Promise((resolve, reject) => {
  resolve("成功")
})

p1.then(res => {
  console.log(res);
})

rejected(失败状态)

const p1 = new Promise((resolve, reject) => {
  reject("失败")
})

p1.then(res => {
  console.log(res);
})

new Promise 干了什么事?

PS: Promise 是一个构造函数,它代表着一个异步操作,可在里面拿到异步回调的结果,判断成功还是失败.

1: Promise对象接收一个实参 (函数 ) ,当Promise new 的时候 这个实参函数 会被马上被立即调用

image.png

2:new Promise 返回的是一个 Promise实例,该实例对象原型身上有一个 then()方法

1651585486(1).jpg

3:该方法接收两个函数 (第一个回调是成功,第二个回调为失败)

这个成功 的函数会赋值给 resolve
1651585691(1).jpg

这个失败 的函数会赋值给 reject
1651585760(1).jpg

当 Promise内部 resolve 时.then 即可拿到成功时的结果 见上图 成功回调

当 Promise内部 reject 时.擦tch 即可拿到失败时的结果 见上图 失败回调

4:Prmise 原型身上还有一个 finally函数 不论是成功还是失败都会执行

1651586212(1).jpg

Promise 状态不可变

Promise 的 三种状态,状态只能从 pending —> Fulfilled 或 pending ----> rejected

当 promise 状态一旦确认了,就无法进行更改了(那怎么确认它的状态呢? 也就是在 resolve 或 reject 时就确认了)

由此可发现当我第二次 reject时候 无法再进行更改了(所以这就是Promise 的状态不可更改)

1651586631(1).jpg

总结 : Promise 执行流程

1: Promise()实例对象接收一个 function 函数 ,当 Promise 对象被new 实例是 function 函数会被立即调用 , 此时 function 函数体内的同步代码会被立即执行,Promise 实例对象的原型(Prototype)上有一个.then 方法 该方法接收两个函数 ((成功回调)=>{},(失败回调)=>) 此时内部会将该函数赋值给 resolve 和reject 当异步代码执行成功时 会调用resolve() 方法 并将 执行成功的代码传给 成功回调 如果代码执行失败 会将失败的 错误信息 err 传给 失败回调,成功时可通过 .then获取结果 失败可通过.catch 获取结果

Promise 身上的静态方法

Promise.all 方法

1.1 .all 方法 传递一个数组作为参数,当所有的Promise 被成功解析时返回的是成功结果的数组,当其中有任何有个Promise 出现了=异常, 则会返回此实例回调失败(reject),失败原因的是第一个失败 promise 的结果,并且在错误之前 之后的promise 结果也不会返回

function requestFirst () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第一个请求返回');
    }, 1000)
  })
}
function requestSecond () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第二个请求返回');
    }, 1000)
  })
}
function requestThird () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第三个请求返回');
    }, 1000)
  })
}

let requestArr = [requestFirst(), requestSecond(), requestThird()]

Promise.all(requestArr).then(res => {
  console.log('结果1', res);
}).catch(err => {
  console.log('错误1', err);
}) 


三个都成功 时 返回成功的结果

1651587674(1).jpg

当有一个出现失败 则返回失败结果

1651587753(1).jpg

如何解决?

1 : 调用 allSettled 方法,该方法不论是正常还是异常都会执行then 方法。 2: 用 try catch 捕获异常当前的异常信息 将其返回

解决方案 1 :

allSettled方法 ----> 不论是错误还是正确都一并返回结果

方案二 : 遍历数据 根据try catch 进行捕获

function one () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第一个请求返回');
    }, 1000)
  })
}
function two () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第二个请求返回');
    }, 1000)
  })
}
function three () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第三个请求返回');
    }, 1000)
  })
}

let arr = [one(), two(), three()]

async function handleAllFunc (fun) {
  try { // 如果结果有错 则把错误捕获并返回  否则返回成功结果
    const res = await fun
    return res
  } catch (error) {
    return error
  }
}
Promise.all(arr.map(item => handleAllFunc(item))).then(res => {
  console.log('成功', res);
}).catch(err => {
  console.log('失败', err);
})

reac方法

race()方法返回一个Promise,当可迭代对象中的一个Promise成功或拒绝时,该Promise 就会根据结果返回带有该Promise的值或错误的原因。

实际上 就是 多个Promise 对象作为参数传递到race 方法中 谁先执行完成先返回谁的值,如果出现错误则返回错误的原因

传递一个Promise返回结果的  数组  //  例: 上方的Promise结果 数组   const arr = [one(), two(), three()]
Promise.race([数组]).then(res => {
  console.log(res);
})

allSettled方法

该方法 一起返回 成功和错误的Promise结果

function one () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第一个请求返回');
    }, 1000)
  })
}
function two () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('这个是错误的');
    }, 1000)
  })
}
function three () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第三个请求返回');
    }, 1000)
  })
}

let requestArr = [one(), two(), three()]


Promise.allSettled(requestArr).then(res => {
//返回失败和成功的结果
  console.log(res);
})

image.png


基本使用就到这里结束了 Async 和 await 放在下篇文中进行讲解,谢谢,欢迎大家评论留言。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值