完全copy from vue-resource (The HTTP client for Vue.js)
https://github.com/pagekit/vue-resource
理解这个实现,则对promise的语法就不难理解了,不然一直云里雾里的死记硬背语法。

1.1 promise构造函数

  1. /**
  2. * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis)
  3. */
  4. // 根据promise对象的三种状态定义三个常量
  5. var RESOLVED = 0;
  6. var REJECTED = 1;
  7. var PENDING = 2;
  8. // 构造函数
  9. function Promise$1(executor) {
  10. this.state = PENDING; // 初始化实例状态为pending
  11. this.value = undefined; // 操作结果,初始化为undefined
  12. this.deferred = []; // 延迟操作数组,既then()添加的成功or失败函数
  13. var promise = this; // 保存this指向,在引入的操作函数中用
  14. try {
  15. executor(function (x) { // 执行操作,并传入实例的resolve/reject方法
  16. promise.resolve(x); // 当传入的操作明确执行成功,调用实例resolve方法
  17. }, function (r) {
  18. promise.reject(r); // 当传入的操作明确执行失败,调用实例reject方法
  19. });
  20. } catch (e) {
  21. promise.reject(e); // 当操作执行过程中,语法或其他意外错误,同样调用实例reject方法
  22. }
  23. }

1.2 原型上挂载的方法

  1. var p$1 = Promise$1.prototype; // 原型
  2. p$1.resolve = function resolve(x) {
  3. var promise = this;
  4. if (promise.state === PENDING) {
  5. if (x === promise) {
  6. throw new TypeError('Promise settled with itself.');
  7. }
  8. var called = false;
  9. try {
  10. var then = x && x['then'];
  11. // 如果操作结果返回的x是另一个promise实例,则当前promise实例的状态则重新由
  12. // 返回的promise实例的状态来决定
  13. if (x !== null && typeof x === 'object' && typeof then === 'function') {
  14. then.call(x, function (x) { // 调用返回的实例的then方法,获取返回的实例的状态
  15. if (!called) {
  16. promise.resolve(x); // 成功,则执行当前实例的resolve,并返回
  17. } // 返回的实例的执行结果
  18. called = true;
  19. }, function (r) {
  20. if (!called) {
  21. promise.reject(r); // 失败
  22. }
  23. called = true;
  24. });
  25. return;
  26. }
  27. } catch (e) {
  28. if (!called) {
  29. promise.reject(e);
  30. }
  31. return;
  32. }
  33. //当执行结果是普通(非promise实例)结果,才会走到这一步,改变状态且执行延迟操作
  34. promise.state = RESOLVED; // 实例状态从pendding-->fulfiled
  35. promise.value = x; // 把操作结果挂载到实例上
  36. promise.notify(); // 触发实例上挂载的延迟操作
  37. }
  38. };
  39. p$1.reject = function reject(reason) {
  40. var promise = this;
  41. if (promise.state === PENDING) {
  42. if (reason === promise) {
  43. throw new TypeError('Promise settled with itself.');
  44. }
  45. // 同上
  46. promise.state = REJECTED;
  47. promise.value = reason;
  48. promise.notify();
  49. }
  50. };
  51. // 触发通过then方法挂载到实例上的延迟操作
  52. // 两种情况会触发,1 操作有结果时,调用resolve/reject实例方法会触发
  53. // 2 调用then实例方法,挂载延迟操作时,会触发,这样可以保证操作和回调解耦的情况下,回调能执行。
  54. p$1.notify = function notify() {
  55. var promise = this;
  56. // nextTick既微任务队列,vue-resouure里面的nextTick直接使用的Vue里面提供的Vue.nextTick,
  57. // Vue里面则根据浏览器宿主环境选择原生promise或者Observe以及setTImeout
  58. nextTick(function () {
  59. // 只有状态变化才会执行队列
  60. if (promise.state !== PENDING) {
  61. while (promise.deferred.length) { // 遍历延迟操作数组
  62. var deferred = promise.deferred.shift(),
  63. onResolved = deferred[0],
  64. onRejected = deferred[1],
  65. resolve = deferred[2],
  66. reject = deferred[3];
  67. try {
  68. if (promise.state === RESOLVED) { // 成功延迟操作
  69. if (typeof onResolved === 'function') {
  70. // 注意:这里的resolve是then方法调用生成的新的promise实例,
  71. //所以这里返回的是新实例的结果
  72. resolve(onResolved.call(undefined, promise.value));
  73. } else {
  74. // 如果函数未传入,则把结果向后推送
  75. resolve(promise.value);
  76. }
  77. } else if (promise.state === REJECTED) { // 失败延迟操作
  78. if (typeof onRejected === 'function') {
  79. // 同理,reject也是新实例的方法,如果处理了失败,
  80. // 失败状态不会向下传递,且新的实例状态为fullfied
  81. resolve(onRejected.call(undefined, promise.value));
  82. } else {
  83. //否则,失败结果会向下传递,这也是为什么失败延迟操作,可以捕获链式
  84. // 调用中,某一环节未被处理的错误
  85. reject(promise.value);
  86. }
  87. }
  88. } catch (e) {
  89. reject(e);
  90. }
  91. }
  92. }
  93. });
  94. };
  95. // 挂载延迟操作回调
  96. p$1.then = function then(onResolved, onRejected) {
  97. var promise = this;
  98. // 返回一个新的实例
  99. return new Promise$1(function (resolve, reject) {
  100. // 向旧的实例的延迟操作队列中push新的
  101. promise.deferred.push([onResolved, onRejected, resolve, reject]);
  102. // 触发执行队列
  103. promise.notify();
  104. });
  105. };
  106. p$1.catch = function (onRejected) {
  107. return this.then(undefined, onRejected);
  108. };

1.3构造函数挂载的方法

  1. //构造函数挂载的reject,用于快速生成一个明确pendding->failed的实例
  2. Promise$1.reject = function (r) {
  3. return new Promise$1(function (resolve, reject) {
  4. reject(r);
  5. });
  6. };
  7. //构造函数挂载的reject,用于快速生成一个明确pendding->fullfied的实例
  8. Promise$1.resolve = function (x) {
  9. return new Promise$1(function (resolve, reject) {
  10. resolve(x);
  11. });
  12. };
  13. Promise$1.all = function all(iterable) {
  14. return new Promise$1(function (resolve, reject) {
  15. var count = 0,
  16. result = [];
  17. if (iterable.length === 0) {
  18. resolve(result);
  19. }
  20. function resolver(i) {
  21. return function (x) {
  22. result[i] = x;
  23. count += 1;
  24. if (count === iterable.length) {
  25. resolve(result);
  26. }
  27. };
  28. }
  29. for (var i = 0; i < iterable.length; i += 1) {
  30. Promise$1.resolve(iterable[i]).then(resolver(i), reject);
  31. }
  32. });
  33. };
  34. Promise$1.race = function race(iterable) {
  35. return new Promise$1(function (resolve, reject) {
  36. for (var i = 0; i < iterable.length; i += 1) {
  37. Promise$1.resolve(iterable[i]).then(resolve, reject);
  38. }
  39. });
  40. };