(详细) 关于Promise!

本文介绍了同步与异步的概念,强调了Promise在异步编程中的重要性。Promise有三个状态:待定、完成和拒绝。它的优点包括灵活的回调函数绑定和链式调用,缺点则包括不可取消、错误处理限制及状态不可逆。文章详细阐述了Promise的创建、状态改变、基本使用流程、链式调用、异常处理以及如何中断Promise链。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

同步和异步

同步

概念:必须等到前一个任务执行完毕之后再执行后一个任务,执行结果按照代码的先后顺序执行,通俗一点来讲,就类似于食堂排队打饭,前一个同学没有打完饭,后一个同学就不能打饭,必须等到前一个同学打完饭才能让后一个同学打饭。
同步任务 指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务.

异步

概念:当前任务的的执行不会阻塞后续任务的执行,我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步.
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
  所有的事件绑定都是异步任务。

Promise

概念:是异步编程的一种新的解决方案(旧的是谁 ?纯回调),解决了以前链式异步调用形成的回调地狱问题。
具体理解:从语法上来说:promise是一个构造函数;
     从功能上来说:promise(实例)对象用来封装一个异步操作并可以获取其结果。

Promise的优缺点

优点
1.指定回调函数的方式更加灵活
纯回调函数:必须在启动异步任务之前
//纯回调函数可能会出现回调地狱的问题:回调函数不断嵌套,什么时候会执行回调嵌套呢?当出现多个串联的异步操作时,而且纯回调函数不便于阅读,也不便于异常处理
promise:启动异步任务=>返回promise对象 =>给promise对象绑定回调函数(甚至可以在异步)
2.支持链式调用,可以解决回调地狱问题

//伪代码
 One().then((result)=> {
        return two(result)
    }).then((secondResult)=>{
        return three(secondResult)
    }).then((finalResult)=>{
        console.log("这是最后一次的返回结果:"+finalResult)
    }).catch(failureCallback)

一旦得到了promise 的新对象,就说明启动了一个异步任务,通过调用.then方法又返回一个新的promise对象中的异步任务中返回的结果,将它作为下一个.then方法的参数.

补充
能够最终解决回调地狱的问题: async/await ; 纯粹的同步编码方式:(没有回调函数的使用)

//伪代码
async function request() {
try{
    const result=await one();
    const secondResult=await two(result);
    const finnalResult=await three(secondResult);
    console.log("这是最后一次的返回结果:"+finnalResult);
}catch(err){
    failureCallback(err)
    }
}

缺点
1.无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3.当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise的三个状态

1.pending(待定):等待态
2.fulfilled(完成):完成态
3.rejected(拒绝):拒绝态
状态改变只有两种可能:
pendding => fulfilled
pendding => rejected
一个promise对象只能改变一次状态,无论是成功还是失败都会有一个结果数据,成功的数据被称之为’value’,失败的数据结果被称之为’reason’

如何改变promise的状态:
resolve(value):如果当前是pendding就会变为fulfilled;
reject(reason):如果当前是pending就会变为rejected
抛出异常:如果当前是pending就会变成rejected

Promise的基本使用流程:

promise对象的基本流程

<script>
    const p = new Promise((resolve, reject) => { //执行器函数  同步回调
        //异步函数执行语句
        setTimeout(() => {
            const time = Date.now();
            //如果 当前时间是奇数,就代表成功
            if (time % 2 == 1) {
                //成功  调用resolve函数,返回一个正确的value数据
                resolve('成功的奇数时间是:'+time)
            } else {
                //失败  调用rejected函数,返回一个错误的reason数据
                reject('失败的偶数时间是:'+ time)
            }
        },1000)
    })
    //调用then方法接收成功的value数据,接收失败的reason数据
    p.then(
        value => {
            //接收成功的value数据
            console.log('成功的回调', value)
        }, reason => {
        //接收失败的reason数据
            console.log('失败的回调', reason)
        }
    )

</script>


如何使用Promise

1.promise使用的API(可暂时理解为语法)
Promise构造函数:Promise(excutor){}
excutor函数:同步执行(resolve,reject)=>{}
resolve函数:内部定义成功时调用的函数 value=>{}
reject函数:内部函数定义失败时调用的函数 reason =>{}
说明:excutor函数会在Promise内部立即同步回调,异步操作在执行器中执行

Promise.prototype.then方法:(onResolved,onRejected)=>{}
onResolved函数:成功时调用的函数(value)=>{}
onRejected函数:失败时调用的函数(reason)=>{}
说明:指定用于得到成功value的成功回调和用于得到失败reasonde的失败回调
返回一个新的Promise对象

Promise.prototype.catch方法: (onRejected)=>{}
onRejected函数:失败的回调函数(reason)=>{}
说明:then()的语法糖,相当于:then(undefined,onRejected)

Promise.prototype.finally方法:
说明:返回一个新的Promise对象,无论结果成功还是失败都会返回

Promise.resolve方法:(value)=>{}
value:成功的数据或Promise对象
说明:返回一个成功或者失败的Promise对象

Promise.reject方法: (reason)=>{}
reason:失败的原因
说明:返回一个失败的Promise对象

Promise.all方法:(promises)=>{}
promises:包含n个promises数组
说明:返回一个新的promise,只有所有的prmise都成功才成功,成功时返回的结果也是一个数组,只要有一个失败了就直接失败了

Promise.race方法:(promises)=>{}
promises:包含n个promise的数组
说明:返回一个新的promise,第一个完成的promise的结果状态就会说最终结果的状态。

改变promise状态和指定回调函数的先后问题

都有可能,正常情况下是先指定回调函数再改变状态,但也乐意先改变状态再指定回调函数
1.先改变状态后指定回调函数
在执行器函数中直接调用resolve()/reject()

延迟更长的的时间采去调用then()
关于什么时候得到数据?
如果先指定回调函数。当状态发生改变时,回调函数会被调用,函数被执行;
如果先改变状态,指定回调函数是,回调函数就会被调用,得到数据

new Promise((resolve,reject))=>{
setTimeout( ()=>{
	resolve(1) //后改变状态 同时指定数据,在异步执行回调函数
},1000);
}).then(//一般情况下是先指定回调函数,保存当前指定的回调函数
	(value)={
		console,log('value1',resolve)},
	(reason)=>{
		console.log('reason1',reason)}
)

//先改变状态 后指定回调函数
new Promise((resolve,reject))=>{
	resolve(1)//先改变状态(同时指定数据)
}).then(//后指定回调函数,异步执行回调函数
	(value)={
		console,log('value2',resolve)},
	(reason)=>{
		console.log('reason2',reason)}
)

(重点)promise.then()返回的新的Promise对象的结果是由什么状态决定的

由then()指定的回调函数执行的结果决定的
具体来说就是:

  • 如果抛出异常,新的promise变为rejected,reason为抛出的异常;
  • 如果return 返回的是非promise的任意值(例如:数字),新的promise对象会变为fulfilled,value中最后返回的值为结果,没有return 返回结果就是undefined;
  • 如果返回的是另一个新的promise,此promise的结果就会成为新promise的结果
<script>
    new Promise((resolve, reject) => {
        resolve(1)
    }).then(
        value => {
            console.log('onResolved1', value)
            // return 2;
            // return Promise.resolve(3);
            //return Promise.reject(4);
            //throw 5;
        },
        reason => {
            console.log('onRejected1', reason)
        }
    ).then(
        value => {
            console.log('onResolved2', value)
        },
        reason => {
            console.log('onRejected2', reason)
        }
    )
</script>

promise如何串联多个任务

  • 利用 promise的then()返回一个新的promise,可以形成then的链式调用,通过then的链式调用串联多个同步或者异步任务
    代码实现如下:
<script>
    new Promise((resolve, reject) => {
        setTimeout(()=>{
            console.log('异步任务一')
            resolve(1)
    },1000)
    }).then(
        value => {
            console.log('任务一的结果:', value)
            console.log('同步任务二')
            return 2;

        }
    ).then(
        value => {
            console.log('任务二的结果:', value)
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    console.log('异步任务三');
                    resolve(3)
                },1000)
            })
        }
    ).then(
        value => {
            console.log('任务三的结果:', value)
        }
    )
</script>

promise的异常传透(逐层传递)

当使用promise的链式调用时,可以在最后指定失败的回调,前面操作出了任何异常都会传到最后的失败回调中处理,但要排除then中包含了错误处理的情况
.then()返回的promise,只有两种情况会失败,要么抛出异常(throw error),要么返回一个失败的promise(Promise.reject())

   new Promise((resolve, reject) => {
        resolve(1)
    }).then(
        value => {
            console.log('onResolved1()', value)
            return 2;
        },
        //当没有异常情况处理时,内部会默认抛出一个异常
       //reason => {throw reason}或者手动添加 return Promise.reject(1)
    ).then(
        value => {
            console.log('onResolved2()', value)
            return 2;
        },
        reason => {throw reason}
    ).then(
        value => {
            console.log('onResolved3()', value)
            return 3;
        },
        reason => {throw reason}
    ).catch((reason)=>{
        console.log('onRejected1()',reason)
    })

如何中断promise链

当使 用promise的链式调用时,在中间中断,不再调用后面 的回调函数,可以让当前的回调函数返回一个处于等待态pending的promise对象

new Promise((resolve, reject) => {
        //resolve(1)
        reject(1)
    }).then(
        value => {
            console.log('onResolved1()', value)
            return 2;
        },
        //当没有异常情况处理时,内部会默认抛出一个异常
        //reason => {throw reason}或者 手动添加 return Promise.reject()
    ).then(
        value => {
            console.log('onResolved3()', value)
            return 3;
        },
        reason => {throw reason}
    ).catch((reason)=>{
        console.log('onRejected1()',reason)
        //中断promise的链式调用 后面的.then方法(回调函数)不再执行
        return new Promise(()=>{})//返回一个处于pending态的promise对象
    }).then(
        value => {
            console.log('onResolved3()', value)
            return 3;
        },
        reason => {throw reason}
    )
### JavaScript Promise 详细介绍 #### 概念与定义 Promise 是一种用于处理异步操作的对象,表示一个异步操作的最终完成(或失败)及其结果值。这使得编写和管理复杂的异步逻辑变得更加简单和直观[^1]。 #### 创建 Promise 对象 可以使用 `new` 关键字创建一个新的 Promise 实例: ```javascript const myFirstPromise = new Promise((resolve, reject) => { // 执行一些异步操作... setTimeout(() => { resolve("成功!"); // 当一切顺利时调用 resolve 函数 }, 250); }); ``` #### 处理 Promise 结果 一旦有了一个 promise,就可以通过 `.then()` 方法链式地注册回调函数来接收其返回的结果;如果发生错误,则可以用 `.catch()` 来捕获异常情况: ```javascript myFirstPromise.then(successMessage => { console.log(successMessage); // 成功消息会被打印出来:"成功!" }).catch(error => { console.error('Error:', error); }); ``` #### 链式调用多个 Promises Promises 支持链式的 then 调用来顺序执行一系列依赖的任务,并且每个任务都可以传递数据给下一个任务: ```javascript function getJSON(url){ return fetch(url).then(response => response.json()); } getJSON('/posts') .then(data => data.title) .then(title => console.log(`文章标题是 ${title}`)) .catch(console.error); ``` #### 并发运行多个 Promises 当有多个独立但并行发生的异步请求时,可利用 `Promise.all([])` 或者 `Promise.race([])` 同时启动它们,在所有都完成后一次性得到全部结果或者只要有一个完成了就立即获得最先的那个结果: ```javascript // 假设有两个 API 请求需要并发发起 let p1 = fetch('/api/user'); let p2 = fetch('/api/settings'); Promise.all([p1, p2]).then(responses => { let userJson = responses[0].json(); let settingsJson = responses[1].json(); return Promise.all([userJson, settingsJson]); }) .then(([user, settings]) => { console.log(user.name + ' likes the color ' + settings.color); }); // 如果只需要第一个完成的结果 Promise.race([p1,p2]) .then(response=>response.text()) .then(text=>console.log(`${text} was loaded first.`)); ``` #### 错误处理的最佳实践 为了确保程序健壮性和用户体验良好,应该始终为每一个可能抛出异常的地方提供相应的 catch handler : ```javascript async function asyncFunction() { try{ const result = await someAsyncOperationThatMightFail(); processResult(result); } catch (error){ handleErrorGracefully(error); } } ``` #### 性能优化建议 对于频繁使用的 promise 序列化场景下考虑缓存已经解析过的 promises 可以提高性能效率减少重复计算开销;另外合理设置超时机制防止长时间未响应的情况影响整体应用体验[^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值