js 异步系列(3) -promise中

2019-08-18  本文已影响0人  Super曲江龙Kimi

上一节promise上已经根据promise/A+规范写出了基本的Promise类的基本框架。

那么在promise/A+规范中还有几个关于then中的规范没有实现。

  1. 如果返回一个普通值,会走下一个then的成功回调
  2. 如果返回一个promise,会将他执行完的状态给下一个then
  3. 如果抛出错误,会走下一个then的reject方法
  4. 返回一个新的promise。实现链式调用

1. 返回一个新的promise。实现链式调用

    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err};
        // 因为then中的回调函数是异步执行的。为了确保newPromise存在,需要setTimeout
        let newPromise = new Promise((resolve, reject) => {
            setTimeout(() => {
                if (this.status === FULFILLED) {
                    // 如果执行then中报错,需要直接reject
                    try {
                         // 执行下then中的方法的返回值当成下一个then的参数传递
                        let x = onFulfilled(this.value);
                        // 返回值有多种情况。普通值或者还是一个promise
                        resolvePromise(newPromise, x, resolve, reject);
                    } catch(err) {
                        reject(err)
                    } 
                }

                if (this.status === REJECTED) {
                    // 如果失败的then中有报错或者还返回一个promise直接向后传递即可
                    let x = onRejected(this.reason);
                    reject(x);
                }

                if (this.status === PENDING) {
                    this.onResolvedCallbacks.push(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(newPromise, x, resolve, reject);
                        } catch(err) {
                            reject(err);
                        }
                    })
                    this.onRejectedCallbacks.push(() => {
                        let x = onRejected(this.reason);
                        reject(x);
                    })
                }
            })
        })
        return newPromise;
    }

2. 如果then中执行后返回的还是一个promise

定义resolvePromise 函数来分情况处理then中返回的结果

const resolvePromise = (promise2, x, resolve, reject) => {
  // 处理x的类型来决定下次then的状态是resolve还是reject
  // promise2 === x的情况就相当于
  // new Promise(resolve => resolve(1)).then(res => a1);
  if (promise2 === x) {
    return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
  }
  let called = false;
  // 判断x是不是一个普通函数 
  if (typeof x === 'object' && x !== null || typeof x === 'function') {
    // 判断是否有then方法来判断是不是promise 
    try {
      let then = x.then;
      if (typeof then === 'function') {
        // 是promise情况 使用then.call来执行x.then方法是为了避免有的对象写的只能获取一次。
        // x.then需要再获取一次 而then.call是上次的缓存
        then.call(x, y => {
          // 参数可能还是promise需要递归
          // .then(res => new Promise(resolve => resolve(new Promise..)))
          resolvePromise(promise2, y, resolve, reject);
        }, r => {
          if (called) return; // 防止多次调用
          called = true;
          reject(r)
        })
      } else { // [1,2,3] {a:1}
        resolve(x);
      }
    } catch(err) {
      if (called) return; // 防止多次调用
      called = true;
      reject(err);
    }
  } else {
    // 不是对象或者函数 普通值
    resolve(x);
  }
}

返回值为promise

如果then中返回promise,也是需要等待这个新的promise执行完毕。直到返回一个resolve()为普通值的promise为止。

new Promise(resolve => resolve(1)).then(res => {
  return new Promise(resolve => resolve(res))
}).then(res => {console.log(2)});

// 所以return 一个new promise,也是要先调用它的then方法返回一个新的promise
// 返回的新的promise继续then讲返回值向后抛
// 和resolve(Promise...) 一样 都是相当于加了2个then
new Promise(resolve => resolve(1))
.then(res => res)
.then(res => res).then(res => res)  // 这两个就相当于新增的2个
.then(res => {
  console.log(2)
});

如果promise当作resolve()的参数或者在then中直接返回。则相当于多加了2次then

Promise.resolve() 和 Promise.reject()

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'));

但是参数是分4种情况的:

(1)参数是一个 Promise 实例

如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

// resolve()参数还是promise则相当于多加两个then
const p = new Promise(resovle => setTimeout(resovle));
new Promise(resolve => resolve(p)).then(() => {
  console.log("3");
});
p.then(() => {
  console.log("1");
}).then(() => {
  console.log("2");
});
// 1 2 3

// 而如果Promise.resolve() 参数中的Promise则是直接替换
const p = new Promise(resovle => setTimeout(resovle));
Promise.resolve(p).then(() => {
  console.log("3");
});
p.then(() => {
  console.log("1");
}).then(() => {
  console.log("2");
});
// 3 1 2

(2)参数是一个thenable对象

thenable对象指的是具有then方法的对象,比如下面这个对象。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

(3)参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

等价于new Promise(resolve => resolve('Hello'));

(4)不带有任何参数

Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve()方法。

const p = Promise.resolve();

p.then(function (res) {
  // res undefined
});

上面代码的变量p就是一个 Promise 对象。

上一篇下一篇

猜你喜欢

热点阅读