zoukankan      html  css  js  c++  java
  • 深入理解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

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

      

  • 相关阅读:
    dynamic和匿名对象
    生成1亿个不重复的8位随机整数
    Storage,Memcache,KVDB都是存储服务,如何区分何时用何种服务
    深入理解jQuery中$.get、$.post、$.getJSON和$.ajax的用法
    常用工具
    数字格式化,保留一位小数,无小数用0补充
    学习某些API的方法
    程序员的学习方法(程序员必看)【风中叶老师讲述】
    html的dtd声明
    数据库管理工具navicat基本使用方法——以MySql为例
  • 原文地址:https://www.cnblogs.com/qiaohong/p/9571687.html
Copyright © 2011-2022 走看看