say high to promise/A+
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
test
.gitattributes
.gitignore
README.md
package-lock.json
package.json
promise.js

README.md

repromise

The project is aim to understand the Promise/A+ better and try to realize an experimental version.

Promise/A+ 核心

  • Promise 操作只会处在 3 种状态的一种:未完成态(pending)、完成态(resolved) 和失败态(rejected);
  • Promise 的状态只会出现从未完成态向完成态或失败态转化;
  • Promise 的状态一旦转化,将不能被更改;

详细地可以参考Promise/A+规范

Feature

文档说明

  • Promise.resolve(): 返回一个状态为 RESOLVED 的 promise 对象

  • Promise.reject(): 返回一个状态为 RESOLVED 的 promise 对象

  • Promise.all(arr): 当数组内所有元素状态都发生改变后,按照顺序返回结果数组

  • Promise.race(arr): 提供竞争机制,返回最早发生状态改变的元素

  • then: 链式调用

  • catch((err) => {}): 错误捕获

  • done((fulfilled) => {}, (err) => {}): 最终错误捕获, 参数可选

  • Promise.wrap(fn): 提供将回调函数 Promise 化的方法

Summary

坑点 1:事件循环

事件循环:同步队列执行完后,在指定时间后再执行异步队列的内容。

之所以要单列事件循环,因为代码的执行顺序与其息息相关,此处用 setTimeout 来模拟事件循环;

下面代码片段中,① 处执行完并不会马上执行 setTimeout() 中的代码(③),而是此时有多少次 then 的调用,就会重新进入 ② 处多少次后,再进入 ③

excuteAsyncCallback(callback, value) {
  const that = this
  setTimeout(function() {
    const res = callback(value) //
    that.excuteCallback('fulfilled', res)
  }, 4)
}

then(onResolved, onRejected) {
  const promise = new this.constructor()
  if (this.state !== 'PENDING') {
    const callback = this.state === 'fulfilled' ? onResolved : onRejected
    this.excuteAsyncCallback.call(promise, callback, this.data)              //
  } else {
    this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) //
  }
  return promise
}

坑点 2:this 的指向问题

this.callbackArr.push() 中的 this 指向的是 ‘上一个’ promise,所以类 CallbackItem 中,this.promise 存储的是'下一个' promise(then 对象)。

class Promise {
  ...
  then(onResolved, onRejected) {
    const promise = new this.constructor()
    if (this.state !== 'PENDING') {        // 第一次进入 then,状态是 RESOLVED 或者是 REJECTED
      const callback = this.state === 'fulfilled' ? onResolved : onRejected
      this.excuteAsyncCallback.call(promise, callback, this.data)  // 绑定 this 到 promise
    } else {                               // 从第二次开始以后,进入 then,状态是 PENDING
      this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // 这里的 this 也是指向‘上一个’ promise
    }
    return promise
  }
  ...
}

class CallbackItem {
  constructor(promise, onResolve, onReject) {
    this.promise = promise // 相应地,这里存储的 promise 是来自下一个 then 的
    this.onResolve = typeof(onResolve) === 'function' ? onResolve : (resolve) => {}
    this.onReject = typeof(onRejected) === 'function' ? onRejected : (rejected) => {}
  }
  ...
}

坑点 3:测试用例 test4.html

new Promise((resolve, reject) => {resolve(Promise.resolve(1))})

类似这种结构的处理稍微有些复杂,日后有好的理解方式再续。调试完代码的感触是:

  1. 还是事件循环
  2. 还是要理清各个闭包存的 that(this) 值

Test

测试与开发顺序相同

此外使用了 promises-aplus-tests 进行相对全面的 Promise/A+ 规范的用例测试,跑通了其提供的全部用例,结果如下:

Use

该项目目前定位为学习项目,欢迎 pr 😁