【问题标题】:Implement Deferred object without using jquery在不使用 jquery 的情况下实现 Deferred 对象
【发布时间】:2013-08-08 10:27:34
【问题描述】:

我想在不使用 jQuery 的情况下实现基本的 Deferred 对象。在这里,我将仅使用解决和拒绝功能实现完成和失败回调。并且当然将promise 方法与此函数相关联。

我正在纯 js 中执行以下实现(已编辑):

function Deferred() {
    var d = {};
    d.resolve = function() {
        d.done(arguments);
    }
    d.reject = function() {
        d.fail(arguments);
    }
    d.promise = function() {
        var x = {};
        x.done = function(args) {
            return args;
        }
        x.fail = function(args) {
            return args;
        }
        return x;
    }
    return d;
}


var v;

var setVal = function() {
    var d = new Deferred();
    setTimeout(function() {
        v = 'a value';
        d.resolve(this);
    }, 5000);
    return d.promise();
};

setVal().done(function() {
    console.log('all done :' + v);
});

但上面给出了错误:Object #<Object> has no method 'fail'

我知道Deferred() 函数的返回对象“d”没有方法 done()。如果我从Deferred() 返回 d.promise,这将没有解决和拒绝功能。

请指出我为实现延迟对象的简单目标而犯了什么错误。

这是我正在做的小提琴:http://jsfiddle.net/SyEmK/14/

【问题讨论】:

  • 如果您使用new 创建实例,那么您应该将方法添加到prototype。构造函数返回一个实例,即使你return d。你可能想要var d = Deferred()
  • 您没有一个名为 done 的方法。如果你看你的对象,你有决心、拒绝和承诺。 setVal() 使用这 3 种方法返回对象的实例。
  • jQuery 并不是唯一实现承诺的库。
  • 误把之前的 coed.. 请查看新编辑的代码..
  • @JayC 我想用纯js实现。 (只是作为一个约束,我必须遵循)..

标签: javascript jquery jquery-deferred deferred


【解决方案1】:
function Deferred(){
  this._done = [];
  this._fail = [];
}
Deferred.prototype = {
  execute: function(list, args){
    var i = list.length;

    // convert arguments to an array
    // so they can be sent to the
    // callbacks via the apply method
    args = Array.prototype.slice.call(args);

    while(i--) list[i].apply(null, args);
  },
  resolve: function(){
    this.execute(this._done, arguments);
  },
  reject: function(){
    this.execute(this._fail, arguments);
  }, 
  done: function(callback){
    this._done.push(callback);
  },
  fail: function(callback){
    this._fail.push(callback);
  }  
}


var v;

var setVal = function() {
    var d = new Deferred();
    setTimeout(function() {
        v = 'a value';
        d.resolve(this);
    }, 5000);
    return d;
};

setVal().done(function() {
    console.log('all done :' + v);
});

【讨论】:

  • 如果你想更接近 jQuery 的行为,你可能想添加一个“promise”函数,它返回一个只有“done”和“fail”的对象(这样调用函数就赢了'无权解决/拒绝)。此外 - 您可以从完成/失败返回“this”,以允许链接。
【解决方案2】:

我认为最好在调用回调后取消分配回调以避免内存泄漏并立即执行稍后添加的回调。

function deferred() {
  let thens = []
  let catches = []

  let status
  let resolvedValue
  let rejectedError

  return {
    resolve: value => {
      status = 'resolved'
      resolvedValue = value
      thens.forEach(t => t(value))
      thens = [] // Avoid memleaks.
    },
    reject: error => {
      status = 'rejected'
      rejectedError = error
      catches.forEach(c => c(error))
      catches = [] // Avoid memleaks.
    },
    then: cb => {
      if (status === 'resolved') {
        cb(resolvedValue)
      } else {
        thens.unshift(cb)
      }
    },
    catch: cb => {
      if (status === 'rejected') {
        cb(rejectedError)
      } else {
        catches.unshift(cb)
      }
    },
  }
}

const d = deferred()

setTimeout(() => {
  d.resolve('good')
}, 1000)

// Will be called after 1s
d.then(value => console.log('#1 resolved!', value))

setTimeout(() => {
  // Will be called after 3s and executed right away as it's already resolved
  d.then(value => console.log('#2 resolved!', value))
}, 3000)

【讨论】:

    【解决方案3】:

    我从未使用过 jquery Deferred,但如果有人来这里寻找 angularjs $q.defer() 的克隆,你所要做的就是这个

    function Defer() {
        const self = this;
        self.promise = new Promise((resolve, reject) => {
            self.resolve = resolve;
            self.reject = reject;
        });
    }
    
    //use it like this
    const deferred = new Defer();
    //then call deferred.resolve(), deferred.reject() and use deferred.promise
    

    【讨论】:

      猜你喜欢
      • 2020-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-09
      • 1970-01-01
      • 1970-01-01
      • 2014-04-04
      • 1970-01-01
      相关资源
      最近更新 更多