承诺/推迟库是如何实现的? [英] How is a promise/defer library implemented?

查看:98
本文介绍了承诺/推迟库是如何实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何实施 q 等承诺/推迟库?我试图阅读源代码,但发现它很难理解,所以我认为如果有人能从高层次向我解释在单线程JS环境中用于实现promise的技术是多么好比如节点和浏览器。

How is a promise/defer library like q implemented? I was trying to read the source code but found it pretty hard to understand, so I thought it'd be great if someone could explain to me, from a high level, what are the techniques used to implement promises in single-thread JS environments like Node and browsers.

推荐答案

我发现解释比展示一个例子更难,所以这里有一个非常简单的实现什么是推迟/承诺。

I find it harder to explain than to show an example, so here is a very simple implementation of what a defer/promise could be.

免责声明:这不是功能实现,并且缺少Promise / A规范的某些部分,这只是为了解释承诺的基础。

Disclaimer: This is not a functional implementation and some parts of the Promise/A specification are missing, This is just to explain the basis of the promises.

tl; dr:转到创建类和示例部分看完全实现。

tl;dr: Go to the Create classes and example section to see full implementation.

首先我们需要创建一个带有数组的promise对象回调。我将开始使用对象,因为它更清晰:

First we need to create a promise object with an array of callbacks. I'll start working with objects because it's clearer:

var promise = {
  callbacks: []
}

现在使用该方法添加回调:

now add callbacks with the method then:

var promise = {
  callbacks: [],
  then: function (callback) {
    callbacks.push(callback);
  }
}

我们也需要错误回调:

var promise = {
  okCallbacks: [],
  koCallbacks: [],
  then: function (okCallback, koCallback) {
    okCallbacks.push(okCallback);
    if (koCallback) {
      koCallbacks.push(koCallback);
    }
  }
}



推迟:



现在创建一个具有承诺的延期对象:

Defer:

Now create the defer object that will have a promise:

var defer = {
  promise: promise
};

需要解决延期:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },
};

需要拒绝:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

请注意,在超时时调用回调以允许代码始终是异步的。

Note that the callbacks are called in a timeout to allow the code be always asynchronous.

这就是基本延迟/承诺实现所需要的。

And that's what a basic defer/promise implementation needs.

现在让我们将两个对象转换为类,首先是promise:

Now lets convert both objects to classes, first the promise:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  then: function (okCallback, koCallback) {
    okCallbacks.push(okCallback);
    if (koCallback) {
      koCallbacks.push(koCallback);
    }
  }
};

现在推迟:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

这是一个使用示例:

function test() {
  var defer = new Defer();
  // an example of an async call
  serverCall(function (request) {
    if (request.status === 200) {
      defer.resolve(request.responseText);
    } else {
      defer.reject(new Error("Status code was " + request.status));
    }
  });
  return defer.promise;
}

test().then(function (text) {
  alert(text);
}, function (error) {
  alert(error.message);
});

正如您所看到的,基本部分简单而小巧。当您添加其他选项时,它会增长,例如多个承诺解析:

As you can see the basic parts are simple and small. It will grow when you add other options, for example multiple promise resolution:

Defer.all(promiseA, promiseB, promiseC).then()

或承诺链接:

getUserById(id).then(getFilesByUser).then(deleteFile).then(promptResult);

要详细了解规格: CommonJS承诺规范。请注意,主库(Q,when.js,rsvp.js,node-promise,...)遵循 Promises / A 规范。

To read more about the specifications: CommonJS Promise Specification. Note that main libraries (Q, when.js, rsvp.js, node-promise, ...) follow Promises/A specification.

希望我足够清楚。

正如评论中所述,我在这个版本中添加了两件事:

As asked in the comments, I've added two things in this version:


  • 调用的可能性然后承诺,无论它有什么状态。

  • 链接承诺的可能性。

为了能够在解决时调用promise,您需要将状态添加到promise中,并在调用then时检查该状态。如果状态已解决或被拒绝,则只需使用其数据或错误执行回调。

To be able to call the promise when resolved you need to add the status to the promise, and when the then is called check that status. If the status is resolved or rejected just execute the callback with its data or error.

为了能够链接承诺,您需要为每次调用<生成新的延迟code>然后并且,当解析/拒绝承诺时,使用回调结果解析/拒绝新承诺。因此,当promise完成时,如果回调返回一个新的promise,它将绑定到使用 then()返回的promise。如果没有,承诺将通过回调结果解决。

To be able to chain promises you need to generate a new defer for each call to then and, when the promise is resolved/rejected, resolve/reject the new promise with the result of the callback. So when the promise is done, if the callback returns a new promise it is bound to the promise returned with the then(). If not, the promise is resolved with the result of the callback.

这是承诺:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  status: 'pending',
  error: null,

  then: function (okCallback, koCallback) {
    var defer = new Defer();

    // Add callbacks to the arrays with the defer binded to these callbacks
    this.okCallbacks.push({
      func: okCallback,
      defer: defer
    });

    if (koCallback) {
      this.koCallbacks.push({
        func: koCallback,
        defer: defer
      });
    }

    // Check if the promise is not pending. If not call the callback
    if (this.status === 'resolved') {
      this.executeCallback({
        func: okCallback,
        defer: defer
      }, this.data)
    } else if(this.status === 'rejected') {
      this.executeCallback({
        func: koCallback,
        defer: defer
      }, this.error)
    }

    return defer.promise;
  },

  executeCallback: function (callbackData, result) {
    window.setTimeout(function () {
      var res = callbackData.func(result);
      if (res instanceof Promise) {
        callbackData.defer.bind(res);
      } else {
        callbackData.defer.resolve(res);
      }
    }, 0);
  }
};

延期:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    var promise = this.promise;
    promise.data = data;
    promise.status = 'resolved';
    promise.okCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, data);
    });
  },

  reject: function (error) {
    var promise = this.promise;
    promise.error = error;
    promise.status = 'rejected';
    promise.koCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, error);
    });
  },

  // Make this promise behave like another promise:
  // When the other promise is resolved/rejected this is also resolved/rejected
  // with the same data
  bind: function (promise) {
    var that = this;
    promise.then(function (res) {
      that.resolve(res);
    }, function (err) {
      that.reject(err);
    })
  }
};

正如你所看到的,它已经增长了很多。

As you can see, it has grown quite a bit.

这篇关于承诺/推迟库是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆