1'use strict'; 2 3// This file contains then/promise specific extensions that are only useful 4// for node.js interop 5 6var Promise = require('./core.js'); 7var asap = require('asap'); 8 9module.exports = Promise; 10 11/* Static Functions */ 12 13Promise.denodeify = function (fn, argumentCount) { 14 if ( 15 typeof argumentCount === 'number' && argumentCount !== Infinity 16 ) { 17 return denodeifyWithCount(fn, argumentCount); 18 } else { 19 return denodeifyWithoutCount(fn); 20 } 21}; 22 23var callbackFn = ( 24 'function (err, res) {' + 25 'if (err) { rj(err); } else { rs(res); }' + 26 '}' 27); 28function denodeifyWithCount(fn, argumentCount) { 29 var args = []; 30 for (var i = 0; i < argumentCount; i++) { 31 args.push('a' + i); 32 } 33 var body = [ 34 'return function (' + args.join(',') + ') {', 35 'var self = this;', 36 'return new Promise(function (rs, rj) {', 37 'var res = fn.call(', 38 ['self'].concat(args).concat([callbackFn]).join(','), 39 ');', 40 'if (res &&', 41 '(typeof res === "object" || typeof res === "function") &&', 42 'typeof res.then === "function"', 43 ') {rs(res);}', 44 '});', 45 '};' 46 ].join(''); 47 return Function(['Promise', 'fn'], body)(Promise, fn); 48} 49function denodeifyWithoutCount(fn) { 50 var fnLength = Math.max(fn.length - 1, 3); 51 var args = []; 52 for (var i = 0; i < fnLength; i++) { 53 args.push('a' + i); 54 } 55 var body = [ 56 'return function (' + args.join(',') + ') {', 57 'var self = this;', 58 'var args;', 59 'var argLength = arguments.length;', 60 'if (arguments.length > ' + fnLength + ') {', 61 'args = new Array(arguments.length + 1);', 62 'for (var i = 0; i < arguments.length; i++) {', 63 'args[i] = arguments[i];', 64 '}', 65 '}', 66 'return new Promise(function (rs, rj) {', 67 'var cb = ' + callbackFn + ';', 68 'var res;', 69 'switch (argLength) {', 70 args.concat(['extra']).map(function (_, index) { 71 return ( 72 'case ' + (index) + ':' + 73 'res = fn.call(' + ['self'].concat(args.slice(0, index)).concat('cb').join(',') + ');' + 74 'break;' 75 ); 76 }).join(''), 77 'default:', 78 'args[argLength] = cb;', 79 'res = fn.apply(self, args);', 80 '}', 81 82 'if (res &&', 83 '(typeof res === "object" || typeof res === "function") &&', 84 'typeof res.then === "function"', 85 ') {rs(res);}', 86 '});', 87 '};' 88 ].join(''); 89 90 return Function( 91 ['Promise', 'fn'], 92 body 93 )(Promise, fn); 94} 95 96Promise.nodeify = function (fn) { 97 return function () { 98 var args = Array.prototype.slice.call(arguments); 99 var callback = 100 typeof args[args.length - 1] === 'function' ? args.pop() : null; 101 var ctx = this; 102 try { 103 return fn.apply(this, arguments).nodeify(callback, ctx); 104 } catch (ex) { 105 if (callback === null || typeof callback == 'undefined') { 106 return new Promise(function (resolve, reject) { 107 reject(ex); 108 }); 109 } else { 110 asap(function () { 111 callback.call(ctx, ex); 112 }) 113 } 114 } 115 } 116}; 117 118Promise.prototype.nodeify = function (callback, ctx) { 119 if (typeof callback != 'function') return this; 120 121 this.then(function (value) { 122 asap(function () { 123 callback.call(ctx, null, value); 124 }); 125 }, function (err) { 126 asap(function () { 127 callback.call(ctx, err); 128 }); 129 }); 130}; 131