1 | const fs = require('fs') console.log('start reading a file...') fs.readFile('file.md', 'utf-8', function (err, content) { if (err) { console.log('error happened during reading the file') return console.log(err) } console.log(content) }) |
将一个函数作为另一个函数的参数,在这个函数的内部可以调用被传递进来的函数(即回调函数)。 这也正是回调函数诞生的原因:如果你将一个函数作为参数传递给另一个函数(此时它被称为高阶函数),那么在函数内部, 你可以调用这个函数来来完成相应的任务。回调函数没有返回值(不要试图用return),仅仅被用来在函数内部执行某些动作。
async1
async.map([1, 2, 3], AsyncSquaringLibrary.square,
function(err, result){
// result will be [1, 4, 9]
});
Promise1
Something.save()
.then(function() {
console.log('success');
})
.catch(function() {
//error handling
})
Generators/ yield
在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。
当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器 会遍历每个中断点。1
function* foo () {
var index = 0;
while (index < 2) {
yield index++; //暂停函数执行,并执行yield后的操作
}
}
var bar = foo(); // 返回的其实是一个迭代器
console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }
co1
co(function* (){
yield Something.save();
}).then(function() {
// success
})
.catch(function(err) {
//error handling
});
Async/ await1
async function save(Something) {
try {
await Something.save(); // 等待await后面的代码执行完,类似于yield
} catch (ex) {
//error handling
}
console.log('success');
}
promise
它表示如A调用一个长时间任务B的时候,B将返回一个”承诺“给A,A不用关心整个实施的过程,继续做自己的任务;当B实施完成的时候,会通过A,并将执行A之间的预先约定的回调。而deferred在英语中语义为:”延迟“,这也说明promise解决的问题是一种带有延迟的事件,这个事件会被延迟到未来某个合适点再执行。
Promise/A+规范:
- Promise 对象有三种状态: Pending – Promise对象的初始状态,等到任务的完成或者被拒绝;Fulfilled – 任务执行完成并且成功的状态;Rejected – 任务执行完成并且失败的状态;
- Promise的状态只可能从“Pending”状态转到“Fulfilled”状态或者“Rejected”状态,而且不能逆向转换,同时“Fulfilled”状态和“Rejected”状态也不能相互转换;
- Promise对象必须实现then方法,then是promise规范的核心,而且then方法也必须返回一个Promise对象,同一个Promise对象可以注册多个then方法,并且回调的执行顺序跟它们的注册顺序一致;
- then方法接受两个回调函数,它们分别为:成功时的回调和失败时的回调;并且它们分别在:Promise由“Pending”状态转换到“Fulfilled”状态时被调用和在Promise由“Pending”状态转换到“Rejected”状态时被调用。
1 | $http.get('/demo1') .then(function(data){ console.log('demo1', data); return $http.get('/demo2', {params: data.result}); }) .then(function(data){ console.log('demo2', data); return $http.get('/demo3', {params: data.result}); }) .then(function(data){ console.log('demo3', data.result); }); $q.all([$http.get('/demo1'), $http.get('/demo2'), $http.get('/demo3') ]) .then(function(results){ console.log('result 1', results[0]); console.log('result 2', results[1]); console.log('result 3', results[2]); }); |
在Angular中的路由机制ngRoute、uiRoute的resolve机制也是采用同样的原理:在路由执行的时候,会将获取模板的Promise、获取所有resolve数据的Promise都拼接在一起,同时并行的获取它们,然后等待它们都结束的时候,才开始初始化ng-view、ui-view指令的scope对象,以及compile模板节点,并插入页面DOM中,完成一次路由的跳转并且切换了View,将静态的HTML模板变为动态的网页展示出来。
使用Promise的方式包装,使得项目Service的返回接口统一。1
var data = $window.localStorage.getItem('data-api-key'); return $q.when(data);
对于延迟任务的Promise DSL语义化封装
Promise是延迟到未来执行某些特定任务,在调用时候则给消费者返回一个”承诺“,消费者线程并不会被阻塞。在消费者接受到”承诺“之后,消费者就不用再关心这些任务是如何完成的,以及督促生产者的任务执行状态等。直到任务完成后,消费者手中的这个”承诺“就被兑现了。1
$modal.open({ templateUrl: '/templates/modal.html', controller: 'ModalController', controllerAs: 'modal', resolve: { } })
.result
.then(function ok(data) { // 用户点击ok按钮事件 }, function cancel(){ // 用户点击cancel按钮事件 });
这是因为modal在open方法的返回值中给了我们一个Promise的result对象(承诺)。等到用户在模态窗口中点击了ok按钮,则Bootstrap会使用$q的defer来resolve来执行ok事件;相反,如果用户点击了cancel按钮,则会使用$q的defer来reject执行cancel事件。
1 | function open(data){ var defer = $q.defer(); // resolve or reject defer; var promise = defer.promise; promise.ok = function(func){ promise.then(func); return promise; }; promise.cancel = function(func){ promise.then(null, func); return promise; }; return promise; }; $modal.open(item) .ok(function(data){ // ok逻辑 }) .cancel(function(data){ // cancel 逻辑 }); promise.success = function(fn) { promise.then(function(response) { fn(response.data, response.status, response.headers, config); }); return promise; }; promise.error = function(fn) { promise.then(null, function(response) { fn(response.data, response.status, response.headers, config); }); return promise; }; |
1 | // 注册一个拦截器服务 $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { return { // 可选方法 'request': function(config) { // 请求成功后处理 return config; }, // 可选方法 'requestError': function(rejection) { // 请求失败后的处理 if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); }, // 可选方法 'response': function(response) { // 返回回城处理 return response; }, // 可选方法 'responseError': function(rejection) { // 返回失败的处理 if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); } }; }); // 将服务注册到拦截器链中 $httpProvider.interceptors.push('myHttpInterceptor'); // 同样也可以将拦截器注册为一个工厂方法。 但上一中方式更为推荐。 $httpProvider.interceptors.push(['$q', function($q) { return { 'request': function(config) { // 同上 }, 'response': function(response) { // 同上 } }; }]); |
这样就可以实现对Angular中的$http或者是$resource的Ajax请求拦截了。但在Angular内部是是如何实现这种拦截方式的呢?Angular使用的就是Promise机制,形成异步管道流,将真实的Ajax请求放置在request、requestError和response、responseError的管道中间,因此就产生了对Ajax请求的拦截。
其源码实现如下:1
var interceptorFactories = this.interceptors = [];
var responseInterceptorFactories = this.responseInterceptors = [];
this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
var defaultCache = $cacheFactory('$http');
var reversedInterceptors = [];
forEach(interceptorFactories, function(interceptorFactory) {
reversedInterceptors.unshift(isString(interceptorFactory) ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
});
forEach(responseInterceptorFactories, function(interceptorFactory, index) {
var responseFn = isString(interceptorFactory) ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory);
reversedInterceptors.splice(index, 0, {
response: function(response) {
return responseFn($q.when(response));
},
responseError: function(response) {
return responseFn($q.reject(response));
}
});
});
...
function $http(requestConfig) {
...
var chain = [serverRequest, undefined];
var promise = $q.when(config);
// apply interceptors
forEach(reversedInterceptors, function(interceptor) {
if (interceptor.request || interceptor.requestError) {
chain.unshift(interceptor.request, interceptor.requestError);
}
if (interceptor.response || interceptor.responseError) {
chain.push(interceptor.response, interceptor.responseError);
}
});
while (chain.length) {
var thenFn = chain.shift();
var rejectFn = chain.shift();
promise = promise.then(thenFn, rejectFn);
}
promise.success = function(fn) {
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
promise.error = function(fn) {
promise.then(null, function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
return promise;
};