黑马程序员技术交流社区

标题: 【上海校区】Hey, 你的Promise [打印本页]

作者: 不二晨    时间: 2018-7-31 09:46
标题: 【上海校区】Hey, 你的Promise
先来看看promise的几种用法:    new Promise((resolve, reject) => resolve()).then(() => {        console.log('success');    }, () => {        console.log('err')    })复制代码如果没有指定reject函数,最后就会执行catch函数new Promise((resolve, reject) => {    reject('err');}).then().catch(e => {    console.log(e); // => Error: err})复制代码Promise.resolve('hahaha').then(data => {    console.log(data); // => 'hahaha'})复制代码Promise.reject('hahaha').then(data => {    console.log(data); // => 'hahaha'})复制代码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.
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);        }    }}复制代码
一个promise必须提供一个then方法去获取当前的或最终的value or reason
promise的then方法有两个参数,分别是成功时执行的方法onFulfilled和失败时执行的方法onRejected
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);            });        }    }}复制代码总结下来就两点:





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




作者: wuqiong    时间: 2018-7-31 10:27

作者: 不二晨    时间: 2018-7-31 11:52
奈斯,很赞
作者: 梦缠绕的时候    时间: 2018-7-31 11:55





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2