Promise 原理解析与实现(遵循Promise/A+规范)

来源:http://www.chinese-glasses.com 作者:Web前端 人气:99 发布时间:2020-03-14
摘要:时间: 2019-12-05阅读: 89标签: Promise1.什么是 Promise 时间: 2018-03-14阅读: 661标签: Promise1.什么是Promise? promise 是目前 JS 异步编程的主流解决方案,遵循 Promises/A+ 方案。 Promise是JS异步编程中的

时间: 2019-12-05阅读: 89标签: Promise1.什么是 Promise

时间: 2018-03-14阅读: 661标签: Promise1.什么是Promise?

promise 是目前 JS 异步编程的主流解决方案,遵循 Promises/A+ 方案。

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一

2.Promise 原理简析

2.对于几种常见异步编程方案回调函数事件监听发布/订阅Promise对象这里就拿回调函数说说

(1)promise 本身相当于一个状态机,拥有三种状态

1.对于回调函数 我们用Jquery的ajax获取数据时 都是以回调函数方式获取的数据

pendingfulfilledrejected一个 promise 对象初始化时的状态是 pending,调用了 resolve 后会将 promise 的状态扭转为 fulfilled,调用 reject 后会将 promise 的状态扭转为 rejected,这两种扭转一旦发生便不能再扭转该 promise 到其他状态。

$.get(url, (data) = { console.log(data))

(2)promise 对象原型上有一个 then 方法,then 方法会返回一个新的 promise 对象,并且将回调函数 return 的结果作为该 promise resolve 的结果,then 方法会在一个 promise 状态被扭转为 fulfilled 或 rejected 时被调用。then 方法的参数为两个函数,分别为 promise 对象的状态被扭转为 fulfilled 和 rejected 对应的回调函数

2.如果说 当我们需要发送多个异步请求 并且每个请求之间需要相互依赖 那这时 我们只能 以嵌套方式来解决 形成 "回调地狱"

3.Promise 如何使用

$.get(url, data1 = { console.log(data1) $.get(data1.url, data2 = { console.log(data1) })})

构造一个 promise 对象,并将要执行的异步函数传入到 promise 的参数中执行,并且在异步执行结束后调用 resolve( ) 函数,就可以在 promise 的 then 方法中获取到异步函数的执行结果

这样一来,在处理越多的异步逻辑时,就需要越深的回调嵌套,这种编码模式的问题主要有以下几个:

new Promise((resolve, reject) = { setTimeout(() = { resolve() }, 1000)}).then( res = {}, err = {})

代码逻辑书写顺序与执行顺序不一致,不利于阅读与维护。异步操作的顺序变更时,需要大规模的代码重构。回调函数基本都是匿名函数,bug 追踪困难。回调函数是被第三方库代码(如上例中的 ajax )而非自己的业务代码所调用的,造成了 IoC 控制反转。Promise 处理多个相互关联的异步请求

同时在 Promise 还为我们实现了很多方便使用的方法:

1.而我们Promise 可以更直观的方式 来解决 "回调地狱"

Promise.resolve

const request = url = { return new Promise((resolve, reject) = { $.get(url, data = { resolve(data) }); })};// 请求data1request(url).then(data1 = { return request(data1.url); }).then(data2 = { return request(data2.url);}).then(data3 = { console.log(data3);}).catch(err = throw new Error(err));

Promise.resolve 返回一个 fulfilled 状态的 promise

2.相信大家在 vue/react 都是用axios fetch 请求数据 也都支持 Promise API

const a = Promise.resolve(1)a.then( res = { // res = 1 }, err = {})
import axios from 'axios';axios.get(url).then(data = { console.log(data)})

Promise.all

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

Promise.all 接收一个 promise 对象数组作为参数,只有全部的 promise 都已经变为 fulfilled 状态后才会继续后面的处理。Promise.all 本身返回的也是一个 promise

3.Promise使用1.Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject

const promise1 = new Promise((resolve, reject) = { setTimeout(() = { resolve('promise1') }, 100)})const promise2 = new Promise((resolve, reject) = { setTimeout(() = { resolve('promise2') }, 100)})const promises = [promise1, promise2]Promise.all(promises).then( res = { // promises 全部变为 fulfilled 状态的处理 }, err = { // promises 中有一个变为 rejected 状态的处理 })
const promise = new Promise((resolve, reject) = { // 异步处理 // 处理结束后、调用resolve 或 reject});

Promise.race

2.promise相当于一个状态机

Promise.race 和 Promise.all 类似,只不过这个函数会在 promises 中第一个 promise 的状态扭转后就开始后面的处理(fulfilled、rejected 均可)

promise的三种状态

const promise1 = new Promise((resolve, reject) = { setTimeout(() = { resolve('promise1') }, 100)})const promise2 = new Promise((resolve, reject) = { setTimeout(() = { resolve('promise2') }, 1000)})const promises = [promise1, promise2]Promise.race(promises).then( res = { // 此时只有 promise1 resolve 了,promise2 仍处于 pending 状态 }, err = {})

pendingfulfilledrejected

配合 async await 使用

1.promise 对象初始化状态为 pending2.当调用resolve(成功),会由pending = fulfilled3.当调用reject(失败),会由pending = rejected

现在的开发场景中我们大多会用 async await 语法糖来等待一个 promise 的执行结果,使代码的可读性更高。async本身是一个语法糖,将函数的返回值包在一个 promise 中返回。

10bet,注意promsie状态 只能由 pending = fulfilled/rejected, 一旦修改就不能再变

// async 函数会返回一个 promiseconst p = async function f() { return 'hello world'}p.then(res = console.log(res)) // hello world

3.promise对象方法

开发技巧

1.then方法注册 当resolve(成功)/reject(失败)的回调函数

在前端开发上 promise 大多被用来请求接口,Axios 库也是开发中使用最频繁的库,但是频繁的 try catch 扑捉错误会让代码嵌套很严重。考虑如下代码的优化方式

// onFulfilled 是用来接收promise成功的值// onRejected 是用来接收promise失败的原因promise.then(onFulfilled, onRejected);
const getUserInfo = async function() { return new Promise((resolve, reject) = { // resolve() || reject() })}// 为了处理可能的抛错,不得不将 try catch 套在代码外边,一旦嵌套变多,代码可读性就会急剧下降try { const user = await getUserInfo()} catch (e) {}

then方法是异步执行的

好的处理方法是在异步函数中就将错误 catch,然后正常返回,如下所示

2.resolve(成功) onFulfilled会被调用

const getUserInfo = async function() { return new Promise((resolve, reject) = { // resolve() || reject() }).then( res = { return [res, null] // 处理成功的返回结果 }, err = { return [null, err] // 处理失败的返回结果 } )}const [user, err] = await getUserInfo()if (err) { // err 处理}// 这样的处理是不是清晰了很多呢
const promise = new Promise((resolve, reject) = { resolve('fulfilled'); // 状态由 pending = fulfilled});promise.then(result = { // onFulfilled console.log(result); // 'fulfilled' }, reason = { // onRejected 不会被调用 })

4.Promise 源码实现

3.reject(失败) onRejected会被调用

知识的学习需要知其然且知其所以然,所以通过一点点实现的一个 promise 能够对 promise 有着更深刻的理解。

const promise = new Promise((resolve, reject) = { reject('rejected'); // 状态由 pending = rejected});promise.then(result = { // onFulfilled 不会被调用 }, reason = { // onRejected console.log(rejected); // 'rejected'})

(1)首先按照最基本的 promise 调用方式实现一个简单的 promise (基于 ES6 规范编写),假设我们有如下调用方式

4.promise.catch

new Promise((resolve, reject) = { setTimeout(() = { resolve(1) }, 1000)}) .then( res = { console.log(res) return 2 }, err = {} ) .then( res = { console.log(res) }, err = {} )

在链式写法中可以捕获前面then中发送的异常,

本文由10bet发布于Web前端,转载请注明出处:Promise 原理解析与实现(遵循Promise/A+规范)

关键词:

最火资讯