Promise:解决JavaScript异步编程难题(一)

引言

在现代的Web开发中,JavaScript异步编程一直是一个备受关注的话题。长期以来,开发者们一直在寻求一种简洁而强大的解决方案,以有效地处理异步操作,避免回调地狱(callback hell)并提高代码的可读性和可维护性。正是在这样的背景下,Promise作为一种解决JavaScript异步编程难题的新思路应运而生。这篇文章,我将教会大家如何使用promise。

异步

异步(asynchronous)是指在程序执行过程中,不需要等待某个操作的完成,而可以继续执行后续的操作。相比于同步(synchronous)操作,异步操作可以提高程序的效率和响应性。

在编程中,异步操作通常用于处理那些耗时较长的任务,如网络请求、文件读写、数据库查询等。在传统的同步编程模型中,程序会在执行这些任务时被阻塞,直到任务完成后才能继续执行后续的代码。而在异步编程模型中,程序可以发起这些任务,然后立即继续执行后续的代码,而不需要等待任务完成。

我们来模拟一下异步:

js 复制代码
function a() {
    setTimeout (() => {
        console.log('阿珍')
    },1000);

}

function b() {
    setTimeout(()=>{
        console.log('阿强')
    },0)
}
a()
b()

a()中我们让阿珍等待1s输出,此时我们的V8先执行b(),等到1s结束后再执行了a(),所以运行结果为=> 阿强 阿珍,这就是异步,先执行a()发现方法需要等待就立刻执行接下来的程序,大大提高了js的执行效率。

异步存在的问题

当我们的b()方法需要依赖a()的结果进行运行,那么掘友们聪明的脑袋瓜子应该能发现,当a()方法还在等待,而需要依赖a()方法结果的b()却提前运行了,这是不符合逻辑的,接下来我们来模拟一下异步的问题

js 复制代码
function a(){
    setTimeout(()=>{
         consol.log('我去相亲了')
    },2000)
   
}
function b(){
    setTimeout(()=>{
         consol.log('我要结婚了')
    },1000)
   
}
a()
b()

显而易见,咱们得先相亲再结婚,并且相亲花费的时间要比结婚长,但是当我们运行程序时,输出的却是先结婚再相亲,这就是异步问题所在

回调地狱

以前的程序是如何解决这个问题的呢?

js 复制代码
function a() {
    setTimeout ((cb) => {
        consol.log('我去相亲了')
        cb()
    },2000);

}

function b() {
    setTimeout(()=>{
        consol.log('我要结婚了')
    },1000)
}
a(b)

以前,程序员们将b()方法放入a()中执行,于是便实现了a()先执行b()再执行。但是,我们的一个项目拥有非常多的方法,很多方法都要依赖别的方法结果来执行,所以程序员们得不停地在方法里回调其他方法,就像将所有的方法串成一根绳子,只要有一个地方断了,所有的程序都会出现错误,这就是回调地狱,使得代码的维护极其困难。

Promise

关于Promise的使用,我们先来看以下代码:

js 复制代码
function xq(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('我相亲了');
            resolve('相亲成功')//可以抛出一个值在.then()接收
        },2000)
    })
}
function marry(){
    return new Promise((resolve, reject) => {
        setTimeout(()=>{
            console.log('我结婚了');
            resolve()
        },1000)
    })
    
}
function baby(){
    setTimeout(()=>{
        console.log('小龙女出生');
    },500)
}
xq().then((res)=>{
    console.log(res);
    return marry()//如果不使用return marry(),那么后面的.then()会调用默认的promise 从而baby()
                  //与marry()一起执行,形成异步
})
.then((res2)=>{    
    baby()
})
  1. xq 函数返回一个Promise对象,表示"我相亲了"这个任务。在Promise中,我们使用setTimeout模拟了一个耗时2秒的相亲过程。当相亲成功后,Promise会调用resolve方法,并传递相亲成功的消息。
  2. marry 函数也返回一个Promise对象,表示"我结婚了"这个任务。在Promise中,我们同样使用setTimeout模拟了一个耗时1秒的结婚过程。当结婚成功后,Promise会调用resolve方法。
  3. baby 函数是一个简单的定时任务,用于模拟"小龙女出生"的过程。
  4. 在主程序中,我们首先调用 xq() 函数,然后使用 .then() 方法来处理相亲成功后的结果。在第一个 .then() 中,我们输出了相亲成功的消息,并调用了 marry() 函数。由于我们在 .then() 中使用了 return marry(),所以后续的 .then() 会等待 marry() 的完成。
  5. 在第二个 .then() 中,我们输出了结婚成功的消息,并调用了 baby() 函数。由于 baby() 函数没有被包裹在Promise中,它会立即执行,而不会等待前面的异步操作完成。

细节

1.resolve 和 reject

在Promise中,resolve和reject是两个函数,用于表示Promise对象的状态。当一个异步操作成功完成时,我们会调用resolve函数来将Promise状态从pending(进行中)变为fulfilled(已成功);当异步操作发生错误或失败时,我们会调用reject函数来将Promise状态从pending变为rejected(已失败)。注意,如果在方法中调用了reject()方法,在全局调用方法时不捕获异常将会报错。

2.return marry()

细心的掘友们会发现,为什么我们在.then()中要return marry()呢?原来是因为如果不使用return marry(),那么后面的.then()会调用默认的promise 从而baby()方法会和marry()方法形成异步。

Promise.all() 和 Promise.race()

关于这两个方法我们先看以下代码:

js 复制代码
function a(){
    return new Promise((resolve,reject) =>{
        setTimeout(()=>{
            console.log('a');
            resolve('yes')//顺利执行 reject() 执行出错
        },2000)
    }) 
}
function b(){
    return new Promise((resolve,reject) =>{
        setTimeout(()=>{
            console.log('b');
            resolve()
        },1500)
    }) 
}
function c(){
    setTimeout(()=>{
        console.log('c');
    })
}
// a()
// b()
// c()
//Promise.all([a(),b()]).then(c)//c 将c函数体传进去 加括号是将c()运行结果传进去
//a(),b() 要有返回promise的能力
//all必须要接收到的所b有的promise状态都为resolve,then才会调用
Promise.race([a(),b()])
.then(c)
.catch((err)=>{
    console.log(err);
})
//a,b谁快.then就接在谁后面执行
  • Promise.all

c 将c函数体传进去 加括号是将c()运行结果传进去,a(),b() 要有返回promise的能力,all必须要接收到的所有的promise状态都为resolve,then才会调用

  • Promise.race

Promise.race会等待a和b中任意一个任务完成,然后立即执行后续的操作。.catch()方法是用来捕获方法中的异常,使其不报错并且更好地找到错误的地方

结尾

希望以上解析能够帮助您理解Promise的基本概念和使用方法。通过合理运用resolve和reject函数、Promise链式调用以及Promise.race等方法,我们可以更好地处理异步操作,实现更灵活、高效的代码设计

相关推荐
饺子大魔王的男人2 小时前
【Three.js】机器人管线包模拟
javascript·机器人
知否技术2 小时前
知道这10个npm工具包,开发效率提高好几倍!第2个大家都用过!
前端·npm
希希不嘻嘻~傻希希3 小时前
CSS 字体与文本样式笔记
开发语言·前端·javascript·css·ecmascript
石小石Orz3 小时前
分享10个吊炸天的油猴脚本,2025最新!
前端
爷_4 小时前
Nest.js 最佳实践:异步上下文(Context)实现自动填充
前端·javascript·后端
爱上妖精的尾巴4 小时前
3-19 WPS JS宏调用工作表函数(JS 宏与工作表函数双剑合壁)学习笔记
服务器·前端·javascript·wps·js宏·jsa
草履虫建模4 小时前
Web开发全栈流程 - Spring boot +Vue 前后端分离
java·前端·vue.js·spring boot·阿里云·elementui·mybatis
—Qeyser4 小时前
让 Deepseek 写电器电费计算器(html版本)
前端·javascript·css·html·deepseek
UI设计和前端开发从业者5 小时前
从UI前端到数字孪生:构建数据驱动的智能生态系统
前端·ui
Junerver6 小时前
Kotlin 2.1.0的新改进带来哪些改变
前端·kotlin