Promise

86 阅读5分钟

Promise

  • Promise 是 JavaScript 中用于处理异步操作的一种机制,它是一种表示异步操作最终完成或失败的对象。使用 Promise 可以更方便地处理异步操作的结果、错误处理以及多个异步操作的串联。

使用基本语法:

     let p = new Promise((resolve,reject) => {
        if(Math.random() > 0.5){
            resolve('成功')
        }else {
            reject('失败')
        }
     }).then(res => {
        console.log('成功的回调')
        
     }).catch(err => {
        console.log('失败的回调')
     })
  • 上述代码创建了一个 Promise 对象 p,在 Promise 的构造函数中,根据随机生成的数值来决定是成功还是失败。
  • 如果生成的随机数大于 0.5,则调用 resolve('成功'),表示 Promise 成功,并传递字符串 '成功' 作为成功的结果。如果生成的随机数小于等于 0.5,则调用 reject('失败'),表示 Promise 失败,并传递字符串 '失败' 作为失败的原因。
  • 随后,通过 then() 方法注册了一个成功的回调函数,用于处理 Promise 成功的情况。在这个例子中,回调函数输出了 '成功的回调'
  • 如果 Promise 失败,则通过 catch() 方法注册了一个失败的回调函数,用于处理 Promise 失败的情况。在这个例子中,回调函数输出了 '失败的回调'

Promise 有三个状态:

  1. Pending(进行中): Promise 的初始状态,表示异步操作正在进行中,尚未完成或失败。
  2. Fulfilled(已完成): 表示异步操作已成功完成,并返回了一个值。
  3. Rejected(已失败): 表示异步操作已失败,返回一个错误信息。
  • 待定状态的 Promise 对象要么会通过一个值被兑现,要么会通过一个原因(错误)被拒绝。当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序也同样会被调用,因此在完成异步操作和绑定处理方法之间不存在竞态条件。
  • 因为 Promise.prototype.thenPromise.prototype.catch方法返回的是 promise,所以它们可以被链式调用。
  • image.png

Promise对象有以下两个特点:

  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,只有异步操作的结果(resolve,reject),可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

示例1:

const p = new Promise((resolve, reject) => {
            // 一般处理一些异步操作
            resolve('success1')
            reject('error')
            resolve('success2')
        })

        p.then(res => {
            console.log(`then : ${res}`)
        }).catch(err => {
            console.log(`catch : ${err}`)
        })
  • 输出为success1,因为一旦状态确定就不会再改变了。

示例2:

  • then的回调执行时机
  const p = new Promise((resolve, reject) => {
            console.log(1)
            resolve() // ==> 先放一放 
            console.log(2)
        })
        p.then((res) => {
            console.log(3)
        })
        console.log(4)
  • 输出 1 、2 、 4 、 3
  • new Promise,这里面的代码是同步的,立即执行,一个一个挨着执行
  • .then()的回调函数,是异步的,要等待同步任务执行完之后才会执行

promise链式调用

  • 链式操作。就是可以.点完了继续点
const arr = [1, 2, 3]
arr.map(el => el * 2).map(el => el * 3).filter(el => el >= 3).map(el => el *3)
  • 因为调用每个map或者filter方法之后,返回值又是一个数组,所以可以链式操作

promise链式调用示例:

       const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('1')
            }, 1000)
        })
      
        p
        .then(res => {
            console.log(`res:${res}`)
            // 过两秒之后,打印2 
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('2')
                }, 2000)
            })
        })
        .then(res => {
                console.log(`res:${res}`)
                // 过三秒之后,打印,3
                return new Promise((resolve, reject) => {
                    setTimeout(() => {
                        resolve('3')
                    }, 3000)
                })
            })
        .then(res => {
                console.log(res)
            })
  • 每一个点then之后,又返回了一个promise对象;这个promise对象又有.then()方法

promise抽离(优化)示例:

  • 用异步的方法实现了同步的功能
       function delay(s) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(`延迟了${s}秒执行`)
                }, s * 1000)
            })
        }

        console.log(delay(1))

        delay(1).then(res => {
            console.log(res)
            return delay(2)
        }).then(res => {
            console.log(res)
            return delay(3)
        }).then(res => {
            console.log(res)
        })
  1. 上述代码定义了一个 delay 函数,它返回一个 Promise 对象,用于实现延迟执行的效果。该函数接受一个参数 s,表示延迟的秒数。
  2. delay 函数中,通过 setTimeout 函数来模拟延迟执行。在指定的延迟时间后,调用 resolve 方法并传递字符串 延迟了${s}秒执行,表示延迟执行成功。
  3. 在主程序中,首先通过 console.log(delay(1)) 打印了一个 Promise 对象。由于 delay(1) 返回的是一个 Promise 对象,而 console.log 函数会打印该对象的引用,所以你会看到一个 Promise 对象的输出。
  4. 接着,通过 delay(1).then() 注册了一个成功的回调函数。当延迟时间为 1 秒的 Promise 对象成功执行时,该回调函数会被触发,将延迟执行的结果打印出来。在这个例子中,输出的结果是 延迟了1秒执行
  5. 接下来,在第一个 then() 的回调函数中,又返回了一个新的 Promise 对象 delay(2)。这样,可以通过链式调用 then() 方法来依次执行多个延迟操作。
  6. 依次类推,每个 then() 中的回调函数会在前一个 Promise 对象成功执行后被触发,将延迟执行的结果打印出来。最终,整个链式调用会依次执行 delay(1)delay(2)delay(3),并输出对应的延迟执行结果。
  • 总结起来,以上代码通过 Promise 实现了多个异步操作的串联执行。每个延迟操作都返回一个 Promise 对象,在每个 Promise 对象成功执行后,会触发下一个 then() 方法中的回调函数,实现了依次延迟执行的效果。

上面示例还可以再简化:

  • 用异步的方法去实现了同步的功能。
 const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

        // console.log(sleep(1000))
        sleep(1000).then(() => {
            console.log(1)
            return sleep(2000)
        }).then(() => {
            console.log(2)
        })