A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 不二晨 金牌黑马   /  2018-7-31 09:46  /  1324 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

先来看看promise的几种用法:
  • Promise.prototype.then:then方法有两个参数,第一个参数是Promise成功时执行的callback,第二个是Promise失败时执行的callback,then方法返回的是一个新的Promise实例
    new Promise((resolve, reject) => resolve()).then(() => {        console.log('success');    }, () => {        console.log('err')    })复制代码
  • Promise.prototype.catch:用于指定发生错误时的回调函数
如果没有指定reject函数,最后就会执行catch函数new Promise((resolve, reject) => {    reject('err');}).then().catch(e => {    console.log(e); // => Error: err})复制代码
  • Promise.resolve:定义在Promise类本身的方法,可以通过Promise.resolve()调用,相当于直接将状态改为成功态
Promise.resolve('hahaha').then(data => {    console.log(data); // => 'hahaha'})复制代码
  • Promise.reject:定义在Promise类本身的方法,可以通过Promise.reject()调用,相当于直接将状态改为失败
Promise.reject('hahaha').then(data => {    console.log(data); // => 'hahaha'})复制代码
  • Promise.prototype.all:将多个Promise执行的结果放到一个数组中返回
let promise1 = new Promise((resolve, reject) => {    setTimeout(() => {          resolve('promise1');    }, 1500);})let promise2 = new Promise((resolve, reject) => {    setTimeout(() => {          resolve('promise2');    }, 2000);})Promise.all([promise1, promise2]).then(data => {    console.log(data); // => ["promise1", "promise2"]})复制代码
  • ...

下面我们自己来实现一个符合 PromiseA+规范 的Promise我们先来简单的用一下promise:
console.log(1)new Promise(() => {    console.log(2)});console.log(3)复制代码因为我们都知道promise是异步的,所以按理会依次输出 1,3,2 然后我们运行之后发现 它依次输出的是 1,2,3 当我们使用then的时候:
console.log(1)Promise.resolve().then(() => {    console.log(2);})console.log(3)复制代码再次运行,发现结果和我们之前想的是一样的,会依次输出 1,3,2 这是因为promise的callback是立即执行的,只有then方法是异步的
A promise must be in one of three states: pending, fulfilled, or rejected.
  • promise必须有三个状态 pending(等待态) fulfilled(成功态) rejected(失败态)
    • 当 state 是 pending 的时候
      • 可以将当前状态改变成其他状态(fulfilled or rejected)
    • 当 state 是 fulfilled 的时候
      • 不能转换成其他状态
      • 必须有一个value(成功之后的值)
    • 当 state 是 rejected 的时候
      • 不能转换成其他状态
      • 必须有一个reason(失败的原因)
class Promise {    constructor(executor) {        // 每一个promise实例都有自己的三个状态,我们用一个变量来保存当前的状态        this.status = 'pending';        // 用来保存执行成功时的值        this.value;        // 用来保存执行失败时的原因        this.reason;                // 用来将当前状态改变为成功态的方法        let resolve = val => {            // 只有当前状态是`pending` 才可以改变状态和值            if (this.status === 'pending') {                this.value = val;                this.status = 'fulfilled';            }        }                // 用来将当前状态改变为失败态的方法        let reject = reason => {            // 只有当前状态是`pending` 才可以改变状态和值            if (this.status === 'pending') {                this.reason = reason;                this.status = 'rejected';            }        }                // 执行executor可能会直接抛出异常,我们用try catch包起来        try {           executor(resolve, reject);         } catch (e) {            // 如果抛出异常,我们直接将状态改为失败态            reject(e);        }    }}复制代码
  • then方法
一个promise必须提供一个then方法去获取当前的或最终的value or reason
promise的then方法有两个参数,分别是成功时执行的方法onFulfilled和失败时执行的方法onRejected
  • onFulfilled 和 onRejected都是可选的参数
    • 如果没传,我们需要设置一个默认方法
  • 如果onFulfilled是一个function
    • 它必须在当前promise的状态变成fulfilled之后被调用,将promise的value(成功之后的值)作为他的第一个参数
    • 在状态是fulfilled之前不能调用它
    • 只能被调用一次
  • 如果onRejected是一个function
    • 它必须在当前promise的状态变成rejected之后被调用,将promise的reason(失败的原因)作为他的第一个参数
    • 在状态是rejected之前不能调用它
    • 只能被调用一次
promise.then(onFulfilled, onRejected)复制代码class Promise {    constructor(executor) {...}        then(onFulfilled, onRejected) {                // 如果当前状态是成功态,我们就执行成功的回调,并将存起来的成功的值value传过去        if (this.status === 'fulfilled') {            onFulfilled(this.value);        }                // 如果当前状态是失败态,我们就执行失败的回调,并将存起来的失败原因reason传过去        if (this.status === 'rejected') {            onRejected(this.reason);        }    }}复制代码好了,我们现在已经可以简单的测试一下了
new Promise((resolve, reject) => {    resolve('完美');}).then(data => {    console.log(data); // => 完美})复制代码完美,但是那么问题来了,如果我们的 resolve 或 reject 是异步的呢?
new Promise((resolve, reject) => {    setTimeout(() => {        resolve('完美');    }, 1000);}).then(data => {    console.log(data); }, err => {    console.log(err);})复制代码运行之后我们发现什么都没有输出,onFulfilled 和 onRejected 都没有打印东西,那说明他们都没有执行,let me think think...
这是因为如果我们的 resolve 或 reject是异步的,当我们的then执行的时候,状态还没有改变,还是pending状态,所以当然什么都不会执行。我们可以先把 onFulfilled 和 onRejected 存起来,等状态改变的时候依次执行对应的callback。A: 这难道是?B: 没错,这就是订阅发布模式。下面我们来改写一下:
class Promise {    constructor(executor) {        this.status = 'pending';        this.value;        this.reason;                // 用来保存成功时执行的回调函数        this.onSuccessCallback = [];                // 用来保存失败时执行的回调函数        this.onErrorCallback = [];                let resolve = val => {            if (this.status === 'pending') {                this.value = val;                this.status = 'fulfilled';                                // 状态改变时 依次执行成功的回调                this.onSuccessCallback.forEach(fn => fn());            }        }                let reject = reason => {            if (this.status === 'pending') {                this.reason = reason;                this.status = 'rejected';                                // 状态改变时 依次执行失败的回调                this.onErrorCallback.forEach(fn => fn());            }        }                // 执行executor可能会直接抛出异常,我们用try catch包起来        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);        }                if (this.status === 'pending') {                    // 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法            this.onSuccessCallback.push(() => {                onFulfilled(this.value);            });                        this.onErrorCallback.push(() => {                onRejected(this.reason);            });        }    }}复制代码
  • onFulfilled 和 onRejected都是异步调用(微任务)
  • onFulfilled 和 onRejected必须作为一个函数被执行
  • then方法必须返回一个promise
    promise2 = promise1.then(onFulfilled, onRejected)复制代码
    • 如果onFulFilled or onRejected返回了一个值x,运行promise解析程序
    • 如果onFulfilled or onRejected抛出了一个异常e,promise2的状态必须是rejected,并将e作为onRejected的参数
    • 如果onFulfilled不是一个function并且promise1是fulfilled,promise2必须也是fulfilled并且使用和promise1相同的value
    • 如果onRejected不是一个function并且promise1是rejected,promise2必须也是rejected并且使用和promise1相同的reason
    我们用promise的时候经常promise.then().then().then() ...这种写法叫链式调用,那怎么样才能继续调用then方法呢,规范规定then方法必须返回一个promise实例,这样就可以实现链式调用了
    class Promise {    contructor() {...}        then(onFulfilled, onRejected) {        // 如果onFulfilled和onFulfilled 不是一个函数,我们给一个默认值        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };        // 我们将所有东西都包到一个promise实例中,最后返回这个实例,这样就可以实现链式调用        let promise2;        // `onFulfilled` 和 `onRejected`都是异步调用,我们先用一个定时器实现异步调用        promise2 = new Promise((resolve, reject) => {            if (this.status === 'fulfilled') {                setTimeout(() => {                    try {                        // 有一个返回值x,运行解析函数resolvePromise                        let x = onFulfilled(this.value);                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e);                    }                }, 0);            }                            if (this.status === 'rejected') {                setTimeout(() => {                    try {                        // 有一个返回值x,运行解析函数resolvePromise                        let x = onRejected(this.reason);;                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e);                    }                }, 0);            }                    if (this.status === 'pending') {                    // 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法                this.onSuccessCallback.push(() => {                    setTimeout(() => {                        try {                            // 有一个返回值x,运行解析函数resolvePromise                            let x = onFulfilled(this.value);                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e);                        }                    }, 0);                });                            this.onErrorCallback.push(() => {                    setTimeout(() => {                        try {                            // 有一个返回值x,运行解析函数resolvePromise                            let x = onRejected(this.reason);;                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e);                        }                    }, 0);                });            }        });        return promise2;    }}复制代码这里可能就会有疑惑了,如果有一个返回值x就运行promise解析程序resolvePromise,这是什么鬼?
    我们先来看看规范:
    promise的解析程序是将promise2和x作为参数的函数
  • 如果promise2和x是一个promise,那么抛出一个TypeError
  • 如果x是一个object或function

    • 使用变量then存储x.then
    • 如果x.then会抛出异常e,调用promise的reject,并将e作为它的参数
    • 如果then是一个function,使用call把它的this指向x,它的第一个参数是resolvePromise,第二个参数是rejectPromise:
      • 当resolvePromise被y值调用的时候,继续执行解析程序
      • 当rejectPromise执行的时候,调用promise的reject并将将失败原因r作为它的参数
    • 如果then不是一个object or function,调用promise的resolve并将x作为它的参数
  • 如果x不是一个object or function,调用promise的resolve并将x作为它的参数

总结下来就两点:
  • 如果promise2和x相等,就抛出一个TypeError,我们先来看一下
    let p = new Promise((resolve, reject) => {    // 返回当前promise实例    return p;});p.then(data => {    console.log(data);}, err => {    console.log(err);});复制代码运行上面代码,我们会发现promise抛出了一个异常,他告诉我们TypeError: Chaining cycle detected for promise,这是因为p的成功还是失败取决于自己,自己再等待自己的执行结果,所以他既不会成功也不会失败

    • 如果onFulFilled or onRejected返回了一个值x,运行promise解析程序resolvePromise
    返回值x有可能是一个常量,对象,也有可能是一个promise,这个程序的作用就是如果 x 是一个promise,那就将 x 一直解析到常量位置
    let p = new Promise((resolve, reject) => {    resolve(new Promise((resolve, reject) => {        resolve(1111);    }))})复制代码let resolvePromise = (promise2, x, resolve, reject) => {    // 如果promise2和x相等,就抛出一个类型错误    if (promise2 === x) {        return reject(new TypeError('错了'));    }    // 只允许调用一次resolvePromise    let called;    // 如果x不是一个常量继续解析    if (x !== null && (typeof x === 'function' || typeof x === 'object')) {        // 调用x.then的时候可能会报错,因为我们有可能和别人的Promise库混用         try {            let then = x.then;                        // 如果then是一个函数,证明x是一个promise,继续解析            if (typeof then === 'function') {                then.call(x, y => {                    if (called) {                        return;                    } else {                        called = true;                    }                    resolvePromise(promise2, y, resolve, reject);                }, r => {                    if (called) {                        return;                    } else {                        called = true;                    }                    reject(r);                })            } else {                // 说明x可能是一个普通对象,不是一个promise                resolve(x);            }        } catch (e) {            if (called) {                return;            } else {                called = true;            }            reject(e);        }    } else {        // 说明x是一个常量,直接执行resolve        resolve(x);    }}复制代码接下来我们来实现Promise.resolve Promise.reject Promise.all
    class Promise {    contructor {...}    then() {...}        // 其实Promise.reject和Promise.reject非常简单    static resolve(value) {        return new Promise((resolve) => {            resolve(value);        })    }    static reject(reason) {        return new Promise((resolve, reject) => {            reject(reason);        })    }        // all方法    static all(promises) {        return new Promise((resolve, reject) => {            // 用来保存结果            let arr = [];            let index = 0;                        const saveData = (i, data) => {                arr = data;                if (++index === promises.length) {                    resolve(arr);                }            }                        for (let i = 0; i < promises.length; i++) {                            promises.then(data => {                    saveData(i, data);                }, reject)            }        })    }}复制代码好了,接下来我们来一个完整版的promise
    class Promise {    contructor() {        this.status = 'pending';        this.value;        this.reason;            // 用来保存成功时执行的回调函数        this.onSuccessCallback = [];                // 用来保存失败时执行的回调函数        this.onErrorCallback = [];            let resolve = val => {            if (this.status === 'pending') {                this.value = val;                this.status = 'fulfilled';                                // 状态改变时 依次执行成功的回调                this.onSuccessCallback.forEach(fn => fn());            }        }            let reject = reason => {            if (this.status === 'pending') {                this.reason = reason;                this.status = 'rejected';                                // 状态改变时 依次执行失败的回调                this.onErrorCallback.forEach(fn => fn());            }        }            // 执行executor可能会直接抛出异常,我们用try catch包起来        try {            executor(resolve, reject);         } catch (e) {            // 如果抛出异常,我们直接将状态改为失败态            reject(e);        }    }        static resolve(value) {        return new Promise((resolve) => {            resolve(value);        })    }    static reject(reason) {        return new Promise((resolve, reject) => {            reject(reason);        })    }        static all(promises) {        return new Promise((resolve, reject) => {            // 用来保存结果            let arr = [];            let index = 0;                        const saveData = (i, data) => {                arr = data;                if (++index === promises.length) {                    resolve(arr);                }            }                        for (let i = 0; i < promises.length; i++) {                            promises.then(data => {                    saveData(i, data);                }, reject)            }        })    }        then(onFulfilled, onRejected) {        // 如果onFulfilled和onFulfilled 不是一个函数,我们给一个默认值        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };        // 我们将所有东西都包到一个promise实例中,最后返回这个实例,这样就可以实现链式调用        let promise2;        // `onFulfilled` 和 `onRejected`都是异步调用,我们先用一个定时器实现异步调用        promise2 = new Promise((resolve, reject) => {            if (this.status === 'fulfilled') {                setTimeout(() => {                    try {                        // 有一个返回值x,运行解析函数resolvePromise                        let x = onFulfilled(this.value);                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e);                    }                }, 0);            }                            if (this.status === 'rejected') {                setTimeout(() => {                    try {                        // 有一个返回值x,运行解析函数resolvePromise                        let x = onRejected(this.reason);;                        resolvePromise(promise2, x, resolve, reject)                    } catch (e) {                        reject(e);                    }                }, 0);            }                    if (this.status === 'pending') {                    // 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法                this.onSuccessCallback.push(() => {                    setTimeout(() => {                        try {                            // 有一个返回值x,运行解析函数resolvePromise                            let x = onFulfilled(this.value);                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e);                        }                    }, 0);                });                            this.onErrorCallback.push(() => {                    setTimeout(() => {                        try {                            // 有一个返回值x,运行解析函数resolvePromise                            let x = onRejected(this.reason);;                            resolvePromise(promise2, x, resolve, reject)                        } catch (e) {                            reject(e);                        }                    }, 0);                });            }        });        return promise2;    }}let resolvePromise = (promise2, x, resolve, reject) => {    // 如果promise2和x相等,就抛出一个类型错误    if (promise2 === x) {        return reject(new TypeError('错了'));    }    // 只允许调用一次resolvePromise    let called;    // 如果x不是一个常量继续解析    if (x !== null && (typeof x === 'function' || typeof x === 'object')) {        // 调用x.then的时候可能会报错,因为我们有可能和别人的Promise库混用         try {            let then = x.then;                        // 如果then是一个函数,证明x是一个promise,继续解析            if (typeof then === 'function') {                then.call(x, y => {                    if (called) {                        return;                    } else {                        called = true;                    }                    resolvePromise(promise2, y, resolve, reject);                }, r => {                    if (called) {                        return;                    } else {                        called = true;                    }                    reject(r);                })            } else {                // 说明x可能是一个普通对象,不是一个promise                resolve(x);            }        } catch (e) {            if (called) {                return;            } else {                called = true;            }            reject(e);        }    } else {        // 说明x是一个常量,直接执行resolve        resolve(x);    }}复制代码





作者:asdff
链接:https://juejin.im/post/5b58300b6fb9a04fea58a27e



3 个回复

倒序浏览
回复 使用道具 举报
奈斯,很赞
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马