promiseA+规范及应用

100 阅读6分钟

什么是Promise

Promise是一种用于异步编程的javascript的对象,解决了回调地狱问题,主要用于处理异步操作的结果。

异步导致的问题

1 回调地狱(代码层级嵌套,不利于代码阅读)

2 错误处理 (无法统一处理错误)

3多个异步操作 (同步结果困难)


Promise解决异步的策略

Promise可以使用.then()方法链式处理异步逻辑

Promise可以使用.catch()方法处理异步操作失败的情况

Promise提供.all()、.race()方法支持处理多个Promise对象 的结果。

PromiseA+规范

概述

1.每个promise 都有三个状态 pending等待态 fulfilled 成 功态 rejected 失败态。
2.每个promise 需要有一个then方法,.then()方法接受两个 回调函数,一个是成功的回调另一个是失败的回调。

3.new Promise中传递的函数会立即执行。

4.promise对象的状态一旦更改后,即不能再改变。(一旦 成功就不能失败,一旦失败就不能成功)。

5.当promise抛出异常后,也会变为失败态

Promise States

promise应该有三种状态(pending, fulflled, rejected).分别代表初始值,成功态 失败态

一旦变更便无法修改

then

promise应该提供一个then方法, 用来访问最终的结果, 无论是value还是reason.

promise.then(onFulfilled, onRejected)

1参数要求

onFulfilled 必须是函数类型, 如果不是函数, 应该被忽略.
onRejected 必须是函数类型, 如果不是函数, 应该被忽略.

2. onFulfilled 特性

在promise变成 fulfilled 时,应该调用 onFulfilled, 参数是value
在promise变成 fulfilled 之前, 不应该被调用.
只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)

3. onRejected 特性

在promise变成 rejected 时,应该调用 onRejected, 参数是reason
在promise变成 rejected 之前, 不应该被调用.
只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)
4. onFulfilled 和 onRejected 应该是微任务
onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用

详见文档

地址:promisesaplus.com/

中文地址:malcolmyu.github.io/malnote/201…

代码实现

实现promiseA+我可以认为分N步完成

 创建promise的时候需要提供一个执行器 executor
	 1.  promise有三个状态 pending态   fulfilled 成功态   rejected失败态
   2.  每个promise都一个then方法,成功和失败的回调
   3.  resolve和reject是两个函数,交给用户使用的 用户可以调用resolve变成成功态
   4.  executor是立刻执行的
   5.  promise 一但状态发生变化后就不能再修改了
   6.  抛出错误也会导致promise失败

1 实现同步逻辑以及基本then方法

  1. 创建promise的时候需要提供一个执行器 executor
  2.  promise有三个状态 pending态   fulfilled 成功态   rejected失败态
  3.  每个promise都一个then方法,成功和失败的回调
  4. resolve和reject是两个函数,交给用户使用的 用户可以调用resolve变成成功态
  5.  executor是立刻执行的
  6. promise 一但状态发生变化后就不能再修改了
  7.  抛出错误也会导致promise失败
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
    constructor(executor){
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        const resolve = (value) =>{
            if(this.status == PENDING){
                this.value = value
                this.status = FULFILLED
            }
        }
        const reject = (reason)=>{
           if(this.status == PENDING){
            this.reason = reason
            this.status = REJECTED
           }
        }
        try{
            executor(resolve,reject)
        }catch(e){
            reject(e)
        }
    }
    then(onFulfilled,onRejected){
        if(this.status === FULFILLED){
            onFulfilled( this.value)
        }
        if(this.status === REJECTED){
            onRejected(this.reason)
        }
    }
}

2 补充promise的异步逻辑,

通过发布订阅,在 onResolvedCallbacks 和onRejectedCallbacks中分别增加成功和失败的回调,实现异步逻辑

...
this.onResolvedCallbacks = []; // then中成功的回调
this.onRejectedCallbacks = []; // then中失败的回调
const resolve = (value) =>{
            if(this.status == PENDING){
                this.value = value
                this.status = FULFILLED
                this.onResolvedCallbacks.forEach(fn=>fn())
            }
        }
const reject = (value) =>{
            if(this.status == PENDING){
                 this.reason = reason
            		 this.status = REJECTED
                this.onRejectedCallbacks.forEach(fn=>fn())
            }
        }
...
then(onFulfilled,onRejected){
         this.onResolvedCallbacks.push(()=>{onFulfilled(this.value)})
         this.onRejectedCallbacks.push(()=>{onRejected(this.reason)})
    }

3 实现连then操作

p1.then((res)=>{new promise(res,req)=>{res('ok')}}
p1.then((res)=>{return false}
p1.then((res)=>{ throw new Error('出错了')}
// 1) 如果一个promise.then中的方法 返回的是一个promise, 那么会自动解析返回的promise。采用他的状态作为下一次then的结果. 会把解析后的值一并传入
// 2) 如果then中方法 返回的不是promise,则会直接走到下一次then的成功
// 3) then中方法抛出异常了 此时会走下一次then的失败

promise实现链式调用采用的是每次调用then方法都会返回一个全新的promise,根据当前then的返回值来判断全新的promise 是成功还是失败。这里采用一个resolvePromise方法进行统一管理,并且要考虑别人promise的实现方法,需要进行更加细致的校验

// 所有的promise都遵循promiseA+规范
// 不同人写的promise可以相互调用
// 这个方法 要考虑x 是不是别人家的promise. 需要对这个x考虑的更细致一些
function resolvePromise(promise2, x, resolve, reject) {
     if (promise2 === x) {
				return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]'))
    }
    if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
        try {
            let then = x.then
            if (typeof then === 'function') {
                then.call(x, function (y) { // 返回的promise成功时调用
                    resolve(y)
                }, function (r) { // 失败的时候调用
                    reject(r)
                })
            } else {
                resolve(x); 
            }
        } catch (e) {
            reject(e);// 取then的时候报错意味着出错了
        }
    } else {
        resolve(x); // 普通值直接成功即可
    }
}

4 根据promiseA+对细节进行完善

let p2 = new Promise((resolve,reject)=>{
    reject(6666);
})
// then方法中的嵌套
p2.then(()=>{
  return new Promise((res,req)=>{
    res(new Promise((res,req)=>{
       res(123)
    }))
 })
})
//onFulfilled onRejected 的初始值
p2.then().then((res)=>{console.log(res)})

其中包括 then方法中的嵌套,onFulfilled onRejected 只能被调用一次,以及onFulfilled onRejected 的初始值,

最终代码

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
console.log('my')


// 所有的promise都遵循promiseA+规范
// 不同人写的promise可以相互调用
// 这个方法 要考虑x 是不是别人家的promise. 需要对这个x考虑的更细致一些
function resolvePromise(promise2, x, resolve, reject) {
    if(promise2 === x){
        return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]'))
    }
    if((typeof x === 'object' && x !== null) || (typeof x === 'function')){
        let called = false;
        try{
            let then = x.then
            if(typeof then === 'function'){
                // 直接采用上一次的取出来的then方法,不要重新取值否则还要触发get
                then.call(x,function(y){ // 返回的promise成功时调用
                    // 递归解析直到是普通值为止
                    if(called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject)
                },function(r){ // 失败的时候调用
                    if(called) return;
                    called = true;
                    reject(r)
                });
            }else{
                // x:{then:{}
                // x:{}
                // x:function
                resolve(x); //说明 then就是一个对象而已 
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);// 取then的时候报错意味着出错了
        }
    }else{
        resolve(x); // 普通值直接成功即可
    }
}
class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;


        this.onResolvedCallbacks = []; // then中成功的回调
        this.onRejectedCallbacks = []; // then中失败的回调
        // 用户调用的成功和失败
        const resolve = (value) => {
            if (this.status == PENDING) {
                this.value = value
                this.status = FULFILLED
                this.onResolvedCallbacks.forEach(fn => fn())
            }
        }
        const reject = (reason) => {
            if (this.status == PENDING) {
                this.reason = reason
                this.status = REJECTED
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }
        try {
            executor(resolve, reject)
        } catch (e) {
            // 如果executor在执行的时候抛出异常了
            // 这个异常就作为失败的原因
            reject(e)
        }
    }
    then(onFulfilled, onRejected) {
         // 值的穿透,没写给你个默认值,让他传递到下一个then中即可
        onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected == 'function' ? onRejected : err=> {throw err}
        let promise2 = new Promise((resolve, reject) => {
            if (this.status === FULFILLED) {
                process.nextTick(() => {
                    try {
                        let x = onFulfilled(this.value)
                        // 用x的值来决定promise2 是成功还是失败
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
            if (this.status === REJECTED) {
                process.nextTick(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
            // 此时还没有确定promise的状态,需要保留成功的回调和失败的回调
            if (this.status === PENDING) {
                // 订阅
                this.onResolvedCallbacks.push(() => {
                    // todo... 可扩展
                    process.nextTick(() => {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        } // AOP 切片
                    })
                })
                this.onRejectedCallbacks.push(() => {
                    // 可扩展
                    process.nextTick(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            }
        })
        return promise2
    }
}
Promise.deferred = function(){
    let dfd = {}
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject
    })
    return dfd
}
// npm install promises-aplus-tests -g
module.exports = Promise; // export default

编写代码验证

通过 npm install promises-aplus-tests -g

然后在当前目录的下输入promises-aplus-tests 目标文件

例如 promises-aplus-tests test