异步编程-Promise

文章目录

  • Promise基本用法
  • Promise应用:ajax
  • Promise 链式调用
  • Promise异常处理
    • 两种方式
    • 两种方式的差异
    • 全局捕获异常事件
  • Promise 静态方法
    • Promise.resolve()
    • Promise.reject()
  • Promise 并行执行
    • Promise.all([])
    • Promise.race([])
  • Promise 执行时序

Promise基本用法

  • Promise相当于承诺某事。若是成功了,会回调resolve方法;若是失败了,会回调reject方法。
  • 两个方法在执行时,会放到队列中执行
console.log(`------------------------------\n----Promise基本用法\n------------------------------`)
//创建“承诺”
const promise = new Promise((resolve, reject) => {
     
    //resolve和reject只会调用一个
    //成功
    // resolve(100)
    //失败
    reject(new Error("this is reject!"))
})
//使用Promise
promise.then((value) => {
     //成功时的回调
    console.log("resolved", value)
}, (error) => {
     //失败时的回调
    console.log("rejected", error)
})
//Promise中无异步处理,但使用Promise.then时,就是异步调用。
//也就是说会将then(resolve,reject)中的resolve和reject方法放到队列中,延后执行
console.log("end of the part")
/**成功(resolve):
 end of the part
 resolved 100
 */
/**失败(reject):
 end of the part
 rejected Error: this is reject!
    at 01.promise.js:14
    at new Promise ()
    at Object. (01.promise.js:8)
    at __webpack_require__ (bootstrap:19)
    at Object. (bootstrap:83)
    at __webpack_require__ (bootstrap:19)
    at bootstrap:83
    at bootstrap:83
 */

Promise应用:ajax

console.log(`------------------------------\n----Promise的ajax使用\n------------------------------`)
const ajax = function (url) {
     
    return new Promise(function (resolve, reject) {
     
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url)
        xhr.responseType = "json"
        xhr.onload = function () {
     
            if (this.status === 200) {
     
                resolve(200)
            } else {
     
                reject(this.statusText)
            }
        }
        xhr.send()
    })
}
ajax("/api/users.jsona").then((value) => {
     
    console.log(value) //200
}, (err) => {
     
    console.log(err) //Not Found
})

Promise 链式调用

  • Promise.then(…)返回的是一个全新的Promise对象
  • 每一个then()方法实际上都是在为上一个then()方法返回的Promise对象去添加状态明确过后的回调。
  • 前面的then()方法中回调函数的返回值会作为后面then()方法回调的参数
  • 如果回调中返回的是Promise,那后面then()方法的回调会等待它的结束
console.log(`------------------------------\n----Promise链式调用\n------------------------------`)
const ajax = function (url) {
     
    return new Promise(function (resolve, reject) {
     
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url)
        xhr.responseType = "json"
        xhr.onload = function () {
     
            if (this.status === 200) {
     
                resolve(200)
            } else {
     
                reject(this.statusText)
            }
        }
        xhr.send()
    })
}
let promise = ajax("/api/users.json")

/** then()方法返回的是Promise对象 */
let promise2 = promise.then(function (value) {
     
    console.log(1111)
})
console.log(promise2) // Promise {}

/** 每次返回的都是一个全新的Promise对象 */
console.log(promise == promise2) //false

/** 执行下一个then()方法需要等待上一个then()方法返回的Promise对象有了明确的状态之后执行 */
let promise3 = promise2.then(function (value) {
     
    console.log(2222)
}).then(function (value) {
     
    console.log(5555)
}).then(function (value) {
     
    console.log(4444)
})
/**结果
 1111
 2222
 5555
 4444
 */
 
/** 上一个then()方法返回的值,是下一个then()方法的回调参数 */
promise3.then(function (value) {
     
    console.log("first:", value)
    return "params test"
}).then(function (value) {
     
    console.log("second:", value)
})
/**结果
 first:undefined
 seconde:params test
 */

Promise异常处理

两种方式

  • 使用onReject回调函数捕获
  • 使用catch()方法捕获
  • catch()方法是then()方法的别名,catch(function(err){…}) === then(undefined,function(err){…})
  • catch()返回的是当前的Promise对象
/** 第一种方式:使用then()方法中的onReject回调函数捕获
 * 捕获的是上一个返回的promise对象出现的异常
 */
ajax("/api/users.json").then(function (value) {
     
    console.log(value)
    noFunction()
}, function (err) {
     
    console.log(err)
})
/**打印
    Uncaught (in promise) ReferenceError: noFunction is not defined
at VERSION (index.js:154)
 */


/** 第二种方式:在then()方法结束后使用catch()方法
 * 捕获的是当前Promise对象出现的异常
 * catch()方法是then()方法的别名,catch(function(err){...}) === then(undefined,function(err){...})
 */
ajax("/api/users.json").then(function (value) {
     
    console.log(value)
    noFunction()
}).catch(function (err) {
     
    console.log(err)
})
/**打印
    ReferenceError: noFunction is not defined
at index.js:166
 */

两种方式的差异

  • 使用onReject回调函数捕获的异常,是上一个返回的promise对象出现的异常
  • 而,使用catch捕获的异常,是当前返回的Promise对象出现的异常
//方式1:
ajax("/api/users.json").then(function (value) {
     
    console.log(value)
    return ajax("/error-url") //异常处
}, function (err) {
     
    console.log(err) //没有捕获
})

//方式2::
ajax("/api/users.json").then(function (value) {
     
    console.log(value)
    return ajax("/error-url") //异常处
}).catch(function (err) {
     
    console.log(err) //Error: Not Found at XMLHttpRequest.xhr.onload (index.js:147)
})

全局捕获异常事件

  • unhandledrejection事件
/** 在window上 */

window.addEventListener('unhandledrejection', event => {
     
    const {
      reason, promise } = event
    // reason :Promise失败原因,一般是一个错误对象
    //promise :出现异常的Promise对象
    event.preventDefault()
}, false)

/** 在node上 */
process.on('unhandledRejection', (reason, promise) => {
     
    console.log(reason, promise)
})

Promise 静态方法

Promise.resolve()

  • 快速创建一个成功的Promise对象
  • 快速的把一个值转换为一个Promise对象。返回的是成功的值,且,在then()方法里,拿到的value也就是这个值
  • 如果传入的值为另一个Promise对象,则Promise.resolve()后的值是原来的Promise对象
  • 如果传入的是带有then方法,且能接受onFulfilled和onRejected参数的对象,同样也可以转换为Promise对象
let promise1 = Promise.resolve("my value")
promise1.then(function (val) {
     
    console.log(val) // my value
})
let promise2 = Promise.resolve(promise1)
console.log(promise1 === promise2) //true
Promise.resolve({
     
    then: function (onFulfilled, onRejected) {
     
        onFulfilled("then object to promise object")
    }
})
    .then(function (value) {
     
        console.log(value) //then object to promise object
    })

Promise.reject()

  • 快速创建一个失败的Promise对象
Promise.reject(new Error("my error in reject static function"))
    .catch(function (err) {
     
        console.log(err) //Error: my error in reject static function
    })

Promise 并行执行

  • 执行多个独立接口时,可使用并行执行

Promise.all([])

  • 接受一个Promise对象数组
  • 等待所有Promise请求完成且成功后,会集体返回一个数组,数组里包含着每个Promise的结果
  • 如果其中有一个Promise请求失败,则会全部失败
    (users.json)
[
    {
     
        "name": "asd",
        "age": 32
    },
    {
     
        "name": "bbb",
        "age": 12
    }
]

(classes.json)

[
    {
     
        "className": "A1班",
        "level": "三年级"
    },
    {
     
        "className": "A5班",
        "level": "二年级"
    }
]

(js)

const ajax = function (url) {
     
    return new Promise(function (resolve, reject) {
     
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url)
        xhr.responseType = "json"
        xhr.onload = function () {
     
            if (this.status === 200) {
     
                resolve(this.response)
            } else {
     
                reject(this.statusText)
            }
        }
        xhr.send()
    })
    }

//全部成功,才会返回成功
//传一个Promise对象数组
let promiseAll = Promise.all([
    ajax("/api/users.json"),
    ajax("/api/classes.json")
])
//返回的是Promise结果数组
promiseAll.then(function (values) {
     
    console.log(values) // [Array(2), Array(2)]
})
//有一个失败,则都会失败
let promiseAllFail = Promise.all([
    ajax("/api/users.json"),
    ajax("/api/none-file.json") //异常处
])
promiseAllFail.then(function (values) {
     
    console.log(values)
}).catch(function (err) {
     
    console.log(err) //Not Found
})
  • 可以在一个json文件中集中管理需请求的链接地址
    (urls.json)
{
     
    "users": "/api/users.json",
    "classes": "/api/classes.json"
}

(js)

ajax("/api/urls.json")
    .then(res => {
     
        const urls = Object.values(res)
        const promiseArray = urls.map(url => ajax(url))
        return Promise.all(promiseArray)
    })
    .then(res => {
     
        console.log(res) //[Array(2), Array(2)]
    })

Promise.race([])

  • 传入一个Promise的数组
  • 返回第一个完成Promise
const ajax = function (url) {
     
    return new Promise(function (resolve, reject) {
     
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url)
        xhr.responseType = "json"
        xhr.onload = function () {
     
            if (this.status === 200) {
     
                resolve(this.response)
            } else {
     
                reject(this.statusText)
            }
        }
        xhr.send()
    })
}
    
const normal = ajax("/api/users.json")
const timeout = new Promise((resolve, reject) => {
     
    setTimeout(() => {
     
        reject("it is timeout!")
    }, 500)
})
Promise.race([
    normal,
    timeout
])
    .then(res => {
     
        console.log(res)
    })
    .catch(err => {
     
        console.log(err) // 在3G网测试下:it is timeout!
    })

Promise 执行时序

  • 微任务:本轮执行任务末尾执行
  • 宏任务:新的一轮任务
  • 目前大部分的异步调用属于 宏任务
  • Promise、MutationObserver、(node中)process.nextTick 属于 微任务
console.log("programming start")
setTimeout(() => {
      //setTimeout方法为宏任务,会在本轮任务全部结束后执行
    console.log("setTimeout")
    new Promise((resolve, reject) => {
     
        console.log("inner promise 1")
        resolve("ok")
    })
        .then(res => {
     
            console.log("inner promise 2")
        })
}, 0)
new Promise((resolve, reject) => {
     //Promise是微任务,会在本轮任务末尾执行
    console.log("promise 1")
    resolve("ok")
})
    .then(res => {
     
        console.log("promise 2")
    })
    .then(res => {
     
        console.log("promise 3")
    })
console.log("programming end")


/**结果
    programming start
    promise 1
    programming end
    promise 2
    promise 3
    setTimeout
    inner promise 1
    inner promise 2
 */

你可能感兴趣的:(javascript深度剖析,promise,javascript)