0%

promise学习笔记总结

promise是一种异步编程的解决方法,相比容易陷入回调地狱的回调函数,采用链式调用的方法更合理也更方便。

promise的了解

promise是一种异步编程的解决方法,相比容易陷入回调地狱的回调函数,采用链式调用的方法更合理也更方便。

promise有三种状态:pending(进行中),fullfilled(已成功)和rejected(已失败),接收一个函数作为参数,该函数有两个参数,分别是resolve和reject两个函数,Promise好比容器,里面存放着一些未来才会执行完毕的事件结果,而这些结果一旦生成是无法改变的。

Promise 新建后会立即执行

1.异步加载图片的例子

function loadImageAsync(url) {
    return new Promise((resolve, reject) => {
        const image = new Image()
        image.onload = function () {
            resolve(image)
        }

        image.onerror = function () {
            reject(new Error())
        }

        image.src = url
    })
}

let url = "https://cdn.jsdelivr.net/gh/inkwall233/imgcdn/vsbg1.png"
loadImageAsync(url).then((res) => {
    console.log(res)
})

2.使用Promise对象实现Ajax操作的例子

const getJSON = function (url) {
    const promise = new Promise((resolve, reject) => {
        const handler = function () {
            if (this.readyState !== 4) {
                return
            }
            if (this.status === 200) {
                resolve(this.response)
            } else {
                reject(new Error(this.statusText))
            }
        }
        const client = new XMLHttpRequest()
        client.open("GET", url)
        client.onreadystatechange = handler
        client.responseType = "json"
        client.setRequestHeader("Accept", "application/json")
        client.send()
    })

    return promise
}

getJSON("http://jsonplaceholder.typicode.com/posts")
    .then((res) => {
    console.log(res)
})
    .catch((err) => {
    console.log(err)
})

Promise的链式调用

Promise.prototype.then()

Promise实例具有then方法,作用是为promise实例添加状态改变时的回调函数

then方法返回的是一个新的Promise实例,

因此可以采用链式写法,即then方法后面再调用另一个then方法。

  1. 每次调用返回的都是一个新的promise实例

  2. 如果then中返回的是一个结果的话,会把这个结果传递下一次then中的成功回调

  3. 如果then中出现异常,会走下一个then的失败回调

  4. 如果then中使用了return,那么return的值会被promise.resolve包装

    Promise.resolve是个把对象包装成promise对象

    Promise.resolve(‘foo’)类似于new Promise(reslove => resolve(‘foo’))

4.Promise.prototype.catch()

此方法是.then(null,rejection)的别名

Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止

getJSON("/post/1.json")
    .then(function (post) {
    return getJSON(post.commentURL)
})
    .then(function (comments) {
    // some code
})
    .catch(function (error) {
    // 处理前面三个Promise产生的错误
})

// 上面代码一共有三个Promise对象:一个由getJSON产生,两个由then()产生,
// 它们之中任何一个抛出的错误,都会被最后一个catch捕获

// 跟传统的try/catch代码块不同的是,如果没有使用catch()方法处理回调函数
// Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
const someAsyncThing = function () {
    return new Promise(function (resolve, reject) {
        // 下面一行会报错,因为x没有声明
        // resolve(x + 2)
    })
}

someAsyncThing().then(function () {
    console.log("everything is great")
})

Promise.prototype.finally()

finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作。

    p6.finally(() => {
        // 语句
      })
      // 等同于
      p6.then(
        (result) => {
          // 语句
          return result
        },
        (error) => {
          // 语句
          throw error
        }
      )

Promise.all()

此方法用于将多个Promise实例,包装成一个新的Promise实例。Promise.all()方法接收一个数组作为参数,p1,p2,p3都是promise实例,如果不是,会调用promise.resolve方法。

  1. 只有p1,p2,p3的状态都变成fulfilled,p的状态才会变成fullfilled,此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数。
  2. 只要其中有一个被rejected,p的状态就会变成rejected

Promise.race()

参数是数组,此方法是将对各promise实例,包装成一个新的Promise实例

只要p1,p2,p3其中一个实例率先改变,p的状态就会跟着改变。那个率先改变的Promise实例的返回值,就会传递给p的回调函数

Promise.allSettled()

参数是一组Promise实例作为参数,包装成一个新的Promise实例。

只有等到这些参数实例都返回结果,不管是fulfilled还是rejected,

包装实例才会结束

该方法返回新的Promise实例,一旦结束,状态总是fulfilled

它的监听函数接收的参数是数组,该数组的每个成员都是一个对象*

对应传入Promise.allSettled()的两个Promise实例。

每个对象都有status属性,属性值只能为fulfilledrejecte

应用场景

有些时候我们不关系异步操作的结果,只关心这些操作有没有结束

这时,Promise.allSettled()就很有用

Promise.any()

此方法和Promise.all()相对应

手撕Promise

class MyPromise {
    constructor(executor) {
        // 初始化state为等待态
        this.state = "pending"
        // 成功的值
        this.value = undefined
        // 失败的原因
        this.reason = undefined
        // 成功存放的数组
        this.onResolvedCallbacks = []
        // 失败存放数组
        this.onRejectedCallbacks = []

        let resolve = (value) => {
            // state改变,resolve调用就会失败
            if (this.state === "pending") {
                // resolve 调用后,state转化为成功态
                this.state = "fulfilled"
                // 储存成功的值
                this.value = value
                // 一旦resolve执行,调用成功数组的函数
                this.onResolvedCallbacks.forEach((fn) => fn())
            }
        }
        let reject = (reason) => {
            // state 改变,reject调用就会失败
            if (this.state === "pending") {
                //reject调用后,state转化为失败态
                this.state = "rejected"
                // 储存失败的原因
                this.reason = reason
                // 一旦reject执行,调用失败数组的函数
                this.onRejectedCallbacks.forEach((fn) => fn())
            }
        }
        // 立即执行exector(),如果exector 执行报错,直接执行reject
        console.log(1)
        try {
            executor(resolve, reject)
        } catch (err) {
            reject(err)
        }
    }
    // then方法
    // then方法中,有两个参数:onFulfilled,onRejected,成功有成功的值,失败有失败的原因
    // 当状态state为fulfilled,则执行onFulfilled,传入this.value。
    // 当状态state为rejected,则执行onRejected,传入this.value

    then(onFulfilled, onRejected) {
        // 状态为fulfilled,执行onFulfilled,传入成功的值

        if (this.state === "fulfilled") {
            onFulfilled(this.value)
        }
        // 状态为rejected,执行onRejected,传入失败的原因
        if (this.state === "rejected") {
            onRejected(this.reason)
        }
        // 当状态state为pending时
        if (this.state === "pending") {
            console.log('then调用');
            // onFulfilled传入到成功数组
            this.onResolvedCallbacks.push(() => {
                onFulfilled(this.value)
            })
            // onRejected传入到失败数组
            this.onRejectedCallbacks.push(() => {
                onRejected(this.reason)
            })
        }
    }
}

let mypromise = new MyPromise((resolve,reject) => {
    setTimeout(()=> resolve('sss'),2000)      
})
console.log(mypromise)
setTimeout(()=>{console.log('1.5s');},1500)
mypromise.then((res) => {
    console.log(res)
})

当resolve在setTimeout内执行,then时state还是pending等待状态,而且then函数也是先执行的

我们就需要在then调用时,将成功和失败存到各自的数组,一旦reject或者resolve,就调用他们

先将then里面的两个函数储存起来,成功或者失败的时候,调用他们。

具体操作是,在then里面判断是pending的情况下,将then的两个参数函数先存储起来

当resolve执行的时候,会拿到值value,再执行then里面的函数。

Promise.all的实现

Promise.resolve =  function(cal){
    return new Promise((resolve,reject) => {
        resolve(val)
    })
}
// Promise的race 方法
// race方法接收一个数组为参数,数组的元素如果不是promise对象
//  就会调用Promise.reslove()
const p = Promise.race([p1,p2,p3])
// race方法,当数组中某一个promise对象的状态率先改变
//  p的状态跟着改变,
// 那个率先改变的promise实例的返回值,就会传递给p的回调函数
Promise.race = function(promises){
    return new Promise((resolve,reject) => {
        for(let i = 0 ; i<promises.length ; i++){
            promises[i].then(resolve,reject)
        }
    })
}

// Promise的all方法
// 获取所有的promise,都执行then,把结果放到一个数组中,一并返回

Promise.all = function(promises){
    let arr = []
    let i = 0
    function processData(index,data){
        arr[index] = data
        i++
        if(i === promises.length){
            resolve(arr)
        }
    }

    return new Promise((resolve,reject) => {
        for(let i=0 ; i<promises.length ; i++){
            promises[i].then(data => {
                processData(i,data)
            },reject)
        }
    })

}

学习于阮一峰老师的ES6入门