先看一个异步调用:
$.get('/api', {
success: onSuccess,
error: onError,
complete: onComplete
});
在上面的异步调用中,必须严谨地设置目标。那么是否有一种先执行异步调用,延迟传递处理的方式呢?答案是Promise/Deferred模式。Promise/Deferred模式 方法允许一个异步函数阻止那些干涉(即直接修改)其内部请求的进度(progress)或状态(status)的其它代码。开发者需提供Promise (承诺)对象所需的业务处理函数,在Deferred中将事件与处理函数进行绑定。
直接看示例代码,如下:
1) 首先定义Promise模块:promise.js
// Created on 2019-12-31
var events = require('events');
var EventEmitter = events.EventEmitter;
var util = require('util');
var Promise = module.exports = function () {
EventEmitter.call(this);
};
util.inherits(Promise, EventEmitter);
Promise.prototype.then = function (fulfilledHandler, errorHandler, progressHandler) {
if (typeof fulfilledHandler === 'function') {
// 利用once()方法,保证成功回调只执行一次
this.once('success', fulfilledHandler);
}
if (typeof errorHandler === 'function') {
// 利用once()方法,保证异常回调只执行一次
this.once('error', errorHandler);
}
if (typeof progressHandler === 'function'){
this.on('progress', progressHandler);
}
return this;
};
2) 第二步定义Deferred模块:deferred.js
// Created on 2019-12-31
var Promise = require('./promise');
var Deferred = module.exports = function () {
this.state = 'unfulfilled';
this.promise = new Promise(); // Deferred与Promise是 has a 的关系
};
Deferred.prototype.resolve = function (obj) {
this.state = 'fulfilled';
this.promise.emit('success', obj);
};
Deferred.prototype.reject = function (err) {
this.state = 'failed';
this.promise.emit('error', err);
};
Deferred.prototype.progress = function (data) {
this.promise.emit('progress', data);
};
3) 使用实例:test.js
// Created on 2019-12-31
var Deferred = require('./deferred');
var http = require('http');
// 使用实例
var promisify = function (res) {
var deferred = new Deferred();
var result = '';
res.on('data', function (chunk) { // data ---> progress
result += chunk;
deferred.progress(chunk);
});
res.on('end', function () { // end ---> success
deferred.resolve(result);
});
res.on('error', function (err) {
deferred.reject(err); // error ---> error
});
return deferred.promise;
};
// 以http调用为例
var options = {
hostname: "www.baidu.com",
method: "GET"
};
var req = http.request(options, function(res){
res.setEncoding('utf8');
promisify(res).then(function () {
console.log("end");
}, function(err) {
console.log("error:", err);
}, function (chunk) {
console.log("Received %s bytes", chunk.length);
});
});
req.end();
执行结果:
Administrator@DESKTOP-MC957MJ MINGW64 /e/NodeJS/test/4_3_2
$ node test.js
Received 8610 bytes
Received 5670 bytes
end
下面直接看一下Promise/Deferred的模块关系图:
理解Deferred/Promise,关键是弄明白test.js里的 promisify(res).then(...); 干了什么。我们一步步看:
先看 promisify(res),我们定义了一个 promisify(res)函数,作用就是绑定http response的res的data、end、error事件侦听器:
res.on('data', function (chunk) { // data ---> progress
result += chunk;
deferred.progress(chunk);
});
res.on('end', function () { // end ---> success
deferred.resolve(result);
});
res.on('error', function (err) {
deferred.reject(err); // error ---> error
});
然后在侦听器中emit Deferred模块的事件信号,从而绑定到Promises的progress,success,error事件侦听器。那Promise的 progress,success,error事件侦听器是什么呢?就是我们需要传入给Promise的事件Handler。即.then(...) 。代码中 (...) 为三个函数,用于响应Deferred模块的progress,success,error事件信号。因此就达到了先执行异步调用,延迟传递处理的目的。