深入理解Promise并写一个符合Promise a+规范的Promise代码

  关于Promise函数可以参考我写的这篇文章https://www.cnblogs.com/qiaohong/p/7705262.html,我们现在就深入理解一下这个函数。

  首先说下Promise方法,Promise方法中还是有些是比较好用的,比如说Promise.all()方法(Promise.all()方法的参数是一个数组,会按照数组的结果放到成功的回调里,如果有一个错误那么就不会成功)、Promise.race()方法(这个方法的参数也是一个数组,Promise.race()会同时发起并发,但是以返回最快的结果为结果,可以用于多台服务器并发的时候用)。代码参考如下

  

let promise = new Promise()
let fs = require(‘mz/fs‘);    //使用了一个mz的包  mz封装了fs对应的函数,并改为Promise
promise.race([fs.readFile(‘./name.txt‘, ‘utf8‘), fs.readFile(‘./age.txt‘, ‘utf8‘)]).then((data) => {
  console.log(data);
}, err => {
  console.log(err);
});

  如何手写Promise a+规范的Promise呢?跟我一步步来,坐稳,看完了你也就懂了。

  先想Pormise的特点:  

  1.每次promise执行then后都会返回一个新的promise
  2.如果then中返回的是一个结果的话会把这个结果传递下一次then中的成功回调
  3.如果then中出现异常 会走下一个then的失败 将错误传递到失败中
  4.如果失败后还可以成功,如果返回undefined 会把undefined 传递给下一次
  5.catch 会捕获到没有捕获的异常
  6.成功或者失败是一个可选参数
  7. 如果then方法返回的是一个promise 那么会等待这个promise执行完决定返回的那个promise是成功还是失败
  8.为什么要返回一个新的promise而不是this promise状态确定后 就是不能更改。

  说干就干,拿起键盘就是怼

  

function Promise(executor) {
  let self = this;
  self.status = ‘pending‘;  //promise默认就是等待状态
  self.value = undefined;   //存放成功回调的值
  self.reason = undefined;  //存放失败回调的值
  self.onResolved = [];  //专门存放成功的回调函数
  self.onRejected = [];  //存放失败的回调函数
  function resolve(value) {  //promise成功走这个函数
    if (self.status === ‘pending‘) {
      self.value = value;
      self.status = ‘resolved‘;
      self.onResolved.forEach(fn => fn());
    }
  }
  function reject(reason) {  //promise失败走这个函数
    if (self.status === ‘pending‘) {
      self.reason = reason;
      self.status = ‘rejected‘;
      self.onRejected.forEach(fn => fn());
    }
  }
  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}
//确定then里面的成功/失败函数执行的结果和返回的promise2是什么关系
//ps:promise a+里面确实有很多的槽点  比如这个x、y和promise2什么的都是那里面规定的
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError(‘循环引用‘));
  }
  let called;
  if (x != null && (typeof x === ‘object‘ || typeof x === ‘function‘)) {
    try {
      let then = x.then; // 如何判断是promise 就判断又没then方法
      if (typeof then === ‘function‘) {
        then.call(x, (y) => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, (e) => {
          if (called) return;
          called = true;
          reject(e);
        });
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}//promise的then方法
Promise.prototype.then = function (onfulfilled, onrejected) {
  onfulfilled = typeof onfulfilled == ‘function‘ ? onfulfilled : val => val;
  onrejected = typeof onrejected === ‘function‘ ? onrejected : err => {
    throw err;
  }
  let self = this;

  let promise2;  //返回新的promise就是promise2  不要问我为什么 a+里面规范的
  promise2 = new Promise((resolve, reject) => {
    if (self.status === ‘resolved‘) {
      setTimeout(() => { // 目的是为了实现异步
        try {
          let x = onfulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    }
    if (self.status === ‘rejected‘) {
      setTimeout(() => {
        try {
          let x = onrejected(self.reason);
          resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
        } catch (e) {
          reject(e);
        }
      }, 0);
    }
    if (self.status === ‘pending‘) {
      self.onResolved.push(function () {
        setTimeout(() => {
          try {
            let x = onfulfilled(self.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
      self.onRejected.push(function () {
        setTimeout(() => {
          try {
            let x = onrejected(self.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
    }
  })
  return promise2;
}//实现promise原生方法
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let results = [];    let i = 0;
    function processData(index, data) {
      results[index] = data; // let arr = []  arr[2] = 100
      if (++i === promises.length) {
        resolve(results);
      }
    }
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      p.then((data) => { // 成功后把结果和当前索引 关联起来
        processData(i, data);
      }, reject);
    }
  })
}
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      p.then(resolve, reject);
    }
  })
}
Promise.prototype.catch = function (onrejected) {
  return this.then(null, onrejected)
}
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value);
  })
}

 // 测试代码是否符合a+ 规范 为了让其能测试
 // npm install promises-aplus-tests -g
 // promises-aplus-tests 文件名 可以测试

Promise.defer = Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
}
module.exports = Promise

  好了这就搞定了,大功告成。

  

原文地址:https://www.cnblogs.com/qiaohong/p/9571687.html

时间: 2024-10-11 03:33:19

深入理解Promise并写一个符合Promise a+规范的Promise代码的相关文章

一起写一个JSON解析器

[本篇博文会介绍JSON解析的原理与实现,并一步一步写出来一个简单但实用的JSON解析器,项目地址:SimpleJSON.希望通过这篇博文,能让我们以后与JSON打交道时更加得心应手.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指正:)] 一.JSON解析器介绍 相信大家在平时的开发中没少与JSON打交道,那么我们平常使用的一些JSON解析库都为我们做了哪些工作呢?这里我们以知乎日报API返回的JSON数据来介绍一下两个主流JSON解析库的用法.我们对地址 http://

自己写一个快速开发android模板

自己写一个快速开发android模板 有时候有些代码以前写过,再开发的时候拿来用,就可以节约很多时间,毕竟写过的以前肯定有所了解,再写一次就没必要了,所以这次自己总结出很多应用都需要的一些共性的东西,写到一个模板,以后直接拿来用.首先分析一下: 1.一个应用,首先需要一个欢迎页面,用于展示公司logo啊,或者应用logo,大概展示两三秒. 2.然后就是登陆注册页面,几乎没有应用是没有登陆注册的吧? 3.打印吐司,activity跳转,activity覆盖别的activity,这些基本方法. 4.

写一个迷你模板引擎

一直想写一个模板引擎用在自己的代码上,因为之前用的一个开源的产品,每次需要变通的时候都会遇到一些局限性,不如自己写的实在,想改哪就改哪,于是今天花了一点时间造了一个很小的模板引擎,核心功能已经存在,其他的待到以后慢慢的扩充. 模板引擎说白了,就是找到页面上的占位符,然后替换掉,再插入到页面中,不管功能还是实现方法都极其简单. 占位符也就两个地方能够出现的: 文本节点 属性值 通过childNodes能够找到文本节点,通过attributes能够找到该元素下的所有存在属性值,所以请看代码,以下代码

使用node.js 文档里的方法写一个web服务器

刚刚看了node.js文档里的一个小例子,就是用 node.js 写一个web服务器的小例子 上代码 (*^▽^*) //helloworld.js// 使用node.js写一个服务器 const http=require('http'); const hostname='127.0.0.1' const port=3000; const server = http.createServer((req,res)=>{ res.statusCode=200; res.setHeader('Cont

自己写一个Promise

参考Promise 的  官方规范  https://promisesaplus.com/ Promise 其实就是一个状态机 它只有两种状态变化 pending    =>   fulfilled pending    =>   rejected 并且状态一旦发生变化后就不会再改变 我们用es5来实现下 先写个架子, 并测试下: function myPromise(executor) { var _this = this; // 保存当前的函数上下文 _this.status = 'pen

关于generator异步编程的理解以及如何动手写一个co模块

generator出现之前,想要实现对异步队列中任务的流程控制,大概有这么一下几种方式: 回调函数 事件监听 发布/订阅 promise对象 第一种方式想必大家是最常见的,其代码组织方式如下: function fn(url, callback){ var httpRequest; //创建XHR httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() : window.ActiveXObject ? new ActiveXObjec

手写基于Promise A+规范的Promise

const PENDING = 'pending';//初始态const FULFILLED = 'fulfilled';//初始态const REJECTED = 'rejected';//初始态function Promise(executor){ let self = this;//先缓存当前promise实例 self.status = PENDING;//设置状态 //定义存放成功的回调的数组 self.onResolvedCallbacks = []; //定义存放失败回调的数组 s

一步一步实现一个Promise A+规范的 Promise

2015年6月,ES2015(即ES6)正式发布后受到了非常多的关注.其中很重要的一点是 Promise 被列为了正式规范. 在此之前很多库都对异步编程/回调地狱实现了类 Promise 的应对方案,比如 bluebird.Angular 的 Q 和大名鼎鼎的 jQuery 的 deffered 等. 为了便于理解,本文将分为三个部分,每个部分实现 Promise 的一部分特性,最终一步一步的实现一个完整的.遵循 promise A+ 规范的 Promise. Promise A+规范规定,Pr

给你一个承诺 - 玩转 AngularJS 的 Promise(转)

在谈论Promise之前我们要了解一下一些额外的知识:我们知道JavaScript语言的执行环境是“单线程”,所谓单线程,就是一次只能够执行一个任务,如果有多个任务的话就要排队,前面一个任务完成后才可以继续下一个任务. 这种“单线程”的好处就是实现起来比较简单,容易操作:坏处就是容易造成阻塞,因为队列中如果有一个任务耗时比较长,那么后面的任务都无法快速执行,或导致页面卡在某个状态上,给用户的体验很差. 当然JavaScript提供了“异步模式”去解决上述的问题,关于“异步模式”JavaScrip