JavaScript中Promise 使用详解

Posted 萌萌的DDD

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中Promise 使用详解相关的知识,希望对你有一定的参考价值。

 Part 01 - Promise 概述

Promise 一种更优的异步编程统一方案

传统的异步编程如ajax:是通过回调函数来进行请求后的一系列执行。

但是如果直接使用传统的回调的方式去完成复杂的异步流程,就无法避免大量的回调函数的嵌套。

这样就容易发生回调地狱,导致代码卡顿

回调地狱

get('url',function(){
    get2('url2',function(){
        get3('url3',function(){
                
            })
        })
    })

最终为了解决回调地狱问题,CommonJS社区提出了Promise方案,最终在ES5被定为标准规范。

Promise是什么?

Promise实际上就是一个对象,用来表述一个异步任务最终结果是成功还是失败。


Part 02 - Promise 基础用法

const promise = new Promise(function(resolve, reject) {
    // 回调函数内部 用于表示承诺的执行、

    // 承诺执行成功
    resolve('resolve200')

    // 承诺执行失败    新建一个失败对象
    reject(new Error('reject500'))
})

promise.then(function(value) {
    // 参数1   resolve函数, 用于执行成功的结果
    console.log(value, 'then');
}, function(err) {
    // 参数2   reject函数, 用于执行失败的结果
    console.log(err, 'error');
})


Part03 - Promise 使用案例

使用promise封装ajax请求的案例

const ajax = function(url) {
    // 封装一个 ajax函数 并将promise作为函数返回值
    return new Promise(function(resolve, reject) {
        // 创建http对象
        var xhr = XMLHttpRequest()
        // 准备发送请求类型和地址
        xhr.open('GET', url)
        // h5新语法  将接收到的数组固定为json格式
        xhr.responseType = 'json'
        xhr.onload = function(res) {
            if (this.status === 200) {
                resolve(res)
            } else {
                reject(new Error(this.statusText))
            }
        }
        xhr.send()
    })
}


ajax('url地址').then(function(value) {
    console.log(value);
}, function(err) {
    console.log(err);
})


Part04 - Promise 的链式调用

Promise的本质也就是使用回调函数,定义异步任务过后所需要执行的任务

而Promise将回调函数分为了两种形式

  •  onFulfilled 成功之后的回调
  • onRejected 失败之后的回调
  • 
    ajax(url)
        .then(function onFulfilled(res) {
            console.log(res);
        }, function onRejected(err) {
            console.log(err);
        })

每一个then方法都会返回一个全新的Promise对象,目的是形成一个以Promise对象为结尾的新的链条。

ajax('url地址').then(function(value) {
        console.log(value);
    }) // => Promise
    .then(function(value) {
        console.log(111);
    }) // => Promise
    .then(function(value) {
        console.log(222);
    }) // => Promise
    .then(function(value) {
        console.log(333);
    }) // => Promise
    .then(function(value) {
        console.log(444);
    }) // => Promise
    .then(function(value) {
        console.log(555);
    }) // => Promise
    .then(function(value) {
        console.log(666);
    })

每次链式调用后的then,实际上都是为了上一个then返回的Promise进行回调后的执行

因此这里的返回则为同步类型  依次执行

ajax('url地址').then(function(value) {
    console.log(value);

    return ajax('url地址').then(function(value) {

        console.log(111);

    })
})

前面then方法中回调函数的返回值会作为后面then方法回调的参数

如果回调中返回的是Promise。那么后面的then方法的回调会等待他的结束 

通过链式调用可以避免多次嵌套回调,保证异步请求的扁平化。


Part05 - Promise 的异常处理

当Promise没有正常请求后,则会执行onRejected函数

或者当resolve函数中出现了异常,或者我们手动抛出了一个一场,那么onRejected函数也会执行

我们可以通过Promise实例的catch方法去注册onRejected回调

ajax('url地址').then(function(value) {
    console.log(value);
}).catch(function(err) {
    console.log(err);
})

unhandledrejection事件

可以抛出在浏览器中没有捕获到的异常

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

    event.preventDefault()
}, false)

Part06 - Promise 的并行执行

当遇到多个可以同时执行的异步任务时,就需要使用 Promise.all

Promise.all()

参数:数组 

数组内部是每一个请求

返回值:数组形式的promise对象

var promise = Promise.all([
    ajax(url1),
    ajax(url2)
])

promise.then(function(res) {
    console.log(res);
})

const p1 = async () => {}
const p2 = async () => {}
const p3 = async () => {}

const [result1, result2, result3] = await Promise.all([p1, p2, p3])

console.log(result1)
console.log(result2)
console.log(result3)

ajax('/api/users.json')
ajax('/api/posts.json')

ajax('/api/urls.json')
  .then(value => {
    const urls = Object.values(value)
    const tasks = urls.map(url => ajax(url))
    return Promise.all(tasks)
  })
  .then(values => {
    console.log(values)
  })

只有所有的请求都结束了,才会返回一个Promise对象

如果其中一个请求失败了,则会返回一个失败的对象。

 Promise.all()等待所有任务结束

Promise.race()当第一个任务完成则返回promise


Part07 - Promise 的执行顺序

即使promise没有任何的异步调用,仍然会被挂起进行异步等待

回调队列中的任务被称之为【宏任务】

宏任务执行的过程中可能临时加上一些额外需求,对于这些额外的需求可以选择作为一个新的宏任务进到队列中排队。

也可以作为当前任务的【微任务】,直接在当前任务结束过后立即执行。

promise的回调则会作为微任务执行。会在本轮调用的末尾进行执行

以上是关于JavaScript中Promise 使用详解的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 中的Promise --- $q服务详解

4.2 前端开发日报——JS异步编程之Promise详解和使用总结

JavaScript中 Promise的学习以及使用

JS 中关于Promise的用法,状态,执行顺序详解,面试可用(原创)

深入 Promise——Promise 实现详解

Javascript-ECMA6-Fetch详解