首页 > 其他分享 >es6-promise-polyfill 自己实现promise.js

es6-promise-polyfill 自己实现promise.js

时间:2024-08-01 17:41:16浏览次数:15  
标签:function es6 resolve polyfill value promise var Promise

 

 

 

https://github.com/lahmatiy/es6-promise-polyfill/blob/master/promise.js

 

 

(function(global){

//
// Check for native Promise and it has correct interface
//

var NativePromise = global['Promise'];
var nativePromiseSupported =
  NativePromise &&
  // Some of these methods are missing from
  // Firefox/Chrome experimental implementations
  'resolve' in NativePromise &&
  'reject' in NativePromise &&
  'all' in NativePromise &&
  'race' in NativePromise &&
  // Older version of the spec had a resolver object
  // as the arg rather than a function
  (function(){
    var resolve;
    new NativePromise(function(r){ resolve = r; });
    return typeof resolve === 'function';
  })();


//
// export if necessary
//

if (typeof exports !== 'undefined' && exports)
{
  // node.js
  exports.Promise = nativePromiseSupported ? NativePromise : Promise;
  exports.Polyfill = Promise;
}
else
{
  // AMD
  if (typeof define == 'function' && define.amd)
  {
    define(function(){
      return nativePromiseSupported ? NativePromise : Promise;
    });
  }
  else
  {
    // in browser add to global
    if (!nativePromiseSupported)
      global['Promise'] = Promise;
  }
}


//
// Polyfill
//

var PENDING = 'pending';
var SEALED = 'sealed';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
var NOOP = function(){};

function isArray(value) {
  return Object.prototype.toString.call(value) === '[object Array]';
}

// async calls
var asyncSetTimer = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout;
var asyncQueue = [];
var asyncTimer;

function asyncFlush(){
  // run promise callbacks
  for (var i = 0; i < asyncQueue.length; i++)
    asyncQueue[i][0](asyncQueue[i][1]);

  // reset async asyncQueue
  asyncQueue = [];
  asyncTimer = false;
}

function asyncCall(callback, arg){
  asyncQueue.push([callback, arg]);

  if (!asyncTimer)
  {
    asyncTimer = true;
    asyncSetTimer(asyncFlush, 0);
  }
}


function invokeResolver(resolver, promise) {
  function resolvePromise(value) {
    resolve(promise, value);
  }

  function rejectPromise(reason) {
    reject(promise, reason);
  }

  try {
    resolver(resolvePromise, rejectPromise);
  } catch(e) {
    rejectPromise(e);
  }
}

function invokeCallback(subscriber){
  var owner = subscriber.owner;
  var settled = owner.state_;
  var value = owner.data_;  
  var callback = subscriber[settled];
  var promise = subscriber.then;

  if (typeof callback === 'function')
  {
    settled = FULFILLED;
    try {
      value = callback(value);
    } catch(e) {
      reject(promise, e);
    }
  }

  if (!handleThenable(promise, value))
  {
    if (settled === FULFILLED)
      resolve(promise, value);

    if (settled === REJECTED)
      reject(promise, value);
  }
}

function handleThenable(promise, value) {
  var resolved;

  try {
    if (promise === value)
      throw new TypeError('A promises callback cannot return that same promise.');

    if (value && (typeof value === 'function' || typeof value === 'object'))
    {
      var then = value.then;  // then should be retrived only once

      if (typeof then === 'function')
      {
        then.call(value, function(val){
          if (!resolved)
          {
            resolved = true;

            if (value !== val)
              resolve(promise, val);
            else
              fulfill(promise, val);
          }
        }, function(reason){
          if (!resolved)
          {
            resolved = true;

            reject(promise, reason);
          }
        });

        return true;
      }
    }
  } catch (e) {
    if (!resolved)
      reject(promise, e);

    return true;
  }

  return false;
}

function resolve(promise, value){
  if (promise === value || !handleThenable(promise, value))
    fulfill(promise, value);
}

function fulfill(promise, value){
  if (promise.state_ === PENDING)
  {
    promise.state_ = SEALED;
    promise.data_ = value;

    asyncCall(publishFulfillment, promise);
  }
}

function reject(promise, reason){
  if (promise.state_ === PENDING)
  {
    promise.state_ = SEALED;
    promise.data_ = reason;

    asyncCall(publishRejection, promise);
  }
}

function publish(promise) {
  var callbacks = promise.then_;
  promise.then_ = undefined;

  for (var i = 0; i < callbacks.length; i++) {
    invokeCallback(callbacks[i]);
  }
}

function publishFulfillment(promise){
  promise.state_ = FULFILLED;
  publish(promise);
}

function publishRejection(promise){
  promise.state_ = REJECTED;
  publish(promise);
}

/**
* @class
*/
function Promise(resolver){
  if (typeof resolver !== 'function')
    throw new TypeError('Promise constructor takes a function argument');

  if (this instanceof Promise === false)
    throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');

  this.then_ = [];

  invokeResolver(resolver, this);
}

Promise.prototype = {
  constructor: Promise,

  state_: PENDING,
  then_: null,
  data_: undefined,

  then: function(onFulfillment, onRejection){
    var subscriber = {
      owner: this,
      then: new this.constructor(NOOP),
      fulfilled: onFulfillment,
      rejected: onRejection
    };

    if (this.state_ === FULFILLED || this.state_ === REJECTED)
    {
      // already resolved, call callback async
      asyncCall(invokeCallback, subscriber);
    }
    else
    {
      // subscribe
      this.then_.push(subscriber);
    }

    return subscriber.then;
  },

  'catch': function(onRejection) {
    return this.then(null, onRejection);
  }
};

Promise.all = function(promises){
  var Class = this;

  if (!isArray(promises))
    throw new TypeError('You must pass an array to Promise.all().');

  return new Class(function(resolve, reject){
    var results = [];
    var remaining = 0;

    function resolver(index){
      remaining++;
      return function(value){
        results[index] = value;
        if (!--remaining)
          resolve(results);
      };
    }

    for (var i = 0, promise; i < promises.length; i++)
    {
      promise = promises[i];

      if (promise && typeof promise.then === 'function')
        promise.then(resolver(i), reject);
      else
        results[i] = promise;
    }

    if (!remaining)
      resolve(results);
  });
};

Promise.race = function(promises){
  var Class = this;

  if (!isArray(promises))
    throw new TypeError('You must pass an array to Promise.race().');

  return new Class(function(resolve, reject) {
    for (var i = 0, promise; i < promises.length; i++)
    {
      promise = promises[i];

      if (promise && typeof promise.then === 'function')
        promise.then(resolve, reject);
      else
        resolve(promise);
    }
  });
};

Promise.resolve = function(value){
  var Class = this;

  if (value && typeof value === 'object' && value.constructor === Class)
    return value;

  return new Class(function(resolve){
    resolve(value);
  });
};

Promise.reject = function(reason){
  var Class = this;

  return new Class(function(resolve, reject){
    reject(reason);
  });
};

})(typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : typeof self != 'undefined' ? self : this);

 

标签:function,es6,resolve,polyfill,value,promise,var,Promise
From: https://www.cnblogs.com/angdh/p/18337156

相关文章

  • await 调用的函数不一定必须是 async 函数。 await 关键字通常用于 async 函数内部,用
    await调用的函数不一定必须是async函数。 await关键字通常用于async函数内部,用来等待一个Promise对象的解决。但如果被await调用的对象不是Promise,那么它会被直接返回。 functionnotPromiseFunction(){return42;}asyncfunctionexample(){const......
  • ES6 Object.freeze()和Object.seal()
    在JavaScript编程中,管理对象的可变性对于保持代码的稳定性和可预测性至关重要。有两个强大的方法可以帮助控制对象属性的变化,它们分别是Object.freeze()和Object.seal()。这篇文章将深入探讨Object.freeze()和Object.seal()的实际用途,并通过实例来说明它们的功能和使用场景,帮助......
  • es6-splice方法例子
    constarr=['a','b','c','d'];////1.1、删除指定位置的一个元素//arr.splice(1,1);//console.log('arr',arr);//["a","c","d"]////1.2、删除指定位置的两个元素/......
  • es6中对数组的常用操作方法-普通数组
    参考https://www.jianshu.com/p/856f4200d3c0最近,经常操作数组,可是数组中的一些常用操作方法很迷糊,看了上面一篇文章之后,茅塞顿开。于是自己按照上面文章的用法,自己全部从头到尾写了一遍,分为普通的数组以及对象数组的操作。//定义数组constarr=[1,2,3,4,5]......
  • es6中对数组的常用操作方法-对象数组
    //定义对象数组constarrayObject=[{name:'name1',title:'title1'},{name:'name2',title:'title2'},{name:'name3',title:'title3'}];//数组对象......
  • 异步操作的华尔兹,Promise详解,在ArkTs如何正确使用?如何使用Promise去封装Sqlite数据库
    目录1.什么是Promise2.Promise中的基本概念3.理解Promise4.Promise的重要方法5.实战我们可以使用Promise去封装一个Splite1.什么是PromisePromise是一种用于异步编程的模式,它提供了一种优雅的方式来处理异步操作的结果,避免了回调地狱问题。在Promise中,每一个Promis......
  • 前端模块化CommonJS、AMD、CMD、ES6
    在前端开发中,模块化是一种重要的代码组织方式,它有助于将复杂的代码拆分成可管理的小块,提高代码的可维护性和可重用性。CommonJS、AMD(异步模块定义)和CMD(通用模块定义)是三种不同的模块规范,它们在定义模块、加载模块以及依赖管理等方面存在差异,并适用于不同的场景。CommonJS、A......
  • 09 ES6的模块化语法
    ECMAScript6(简称ES6)是JavaScript语言的下一代标准,其中引入了许多新特性,包括模块化语法。ES6的模块化语法允许开发者将代码分割成独立的模块,每个模块可以包含变量、函数和其他资源,并且可以在不同的文件中进行导入和导出。导出模块(Export)在ES6中,可以使用export关键字来导出......
  • 视野修炼-技术周刊第93期 | polyfill.io 投毒
    欢迎来到第93期的【视野修炼-技术周刊】,下面是本期的精选内容简介......
  • vue3 Promise处理异步操作的对象
    Promise是JavaScript中用于处理异步操作的一种对象。它代表了一个异步操作的最终完成(或失败)及其结果值。在处理异步操作时,Promise提供了一种更干净、更可读的方式来管理回调函数。Promise的状态一个Promise对象有三种状态:Pending(进行中):初始状态,操作尚未完成。Fulfille......