2013-06-23 41 views
2

我想爲我的nodejs服務器應用程序創建一個上傳中間件。這個nodejs中間件使用打字稿的範圍

我用的打字稿:

/// <reference path="./Scripts/typings/express/express.d.ts" /> 
/// <reference path="./Scripts/typings/async/async.d.ts" /> 

import file = module('modules/fileupload_file'); 
import async = module('async'); 

export class FileUpload { 
    private uploadDelegate: any; 

    constructor(options) { 
     this.uploadDelegate = options.adapter || new file.filesystem(options); 
     console.log(this.uploadDelegate); 
    } 

    middleware(req: ExpressServerRequest, res: ExpressServerResponse, next) { 
     if (typeof req.files === 'undefined' || Object.keys(req.files).length === 0) { 
      return next() 
     } 

     async.each(Object.keys(req.files), (field, cb) => { 
      var files = req.files[field], 
       filesArray = []; 

      if (!Array.isArray(files)) 
       files = [files]; 

      async.each(files, (file, cb1) => { 
       filesArray = []; 

       if (typeof file.path === 'undefined' || file.size === 0) { 
        return cb1(null); 

       } 
       console.log(this); 
       this.uploadDelegate.put(file, function (error, storedFile) { 
        filesArray.push(storedFile); 
        cb1(null); 
       }); 

      }, (err: string) => {  
       console.log(err); 
       console.log(field);   
       console.log(filesArray); 

       req.body[field] = filesArray; 
       cb(null); 

      }); 
     }, next); 
    } 
} 

這個變成:

var file = require("./modules/fileupload_file"); 
var async = require('async'); 

var FileUpload = (function() { 
    function FileUpload(options) { 
     this.uploadDelegate = options.adapter || new file.filesystem(options); 
     console.log(this.uploadDelegate); 
    } 
    FileUpload.prototype.middleware = function (req, res, next) { 
     var _this = this; 
     if (typeof req.files === 'undefined' || Object.keys(req.files).length === 0) { 
      return next(); 
     } 

     async.each(Object.keys(req.files), function (field, cb) { 
      var files = req.files[field], filesArray = []; 

      if (!Array.isArray(files)) 
       files = [files]; 

      async.each(files, function (file, cb1) { 
       filesArray = []; 

       if (typeof file.path === 'undefined' || file.size === 0) { 
        return cb1(null); 
       } 
       console.log(_this); 
       _this.uploadDelegate.put(file, function (error, storedFile) { 
        filesArray.push(storedFile); 
        cb1(null); 
       }); 
      }, function (err) { 
       console.log(err); 
       console.log(field); 
       console.log(filesArray); 

       req.body[field] = filesArray; 
       cb(null); 
      }); 
     }, next); 
    }; 
    return FileUpload; 
})(); 
exports.FileUpload = FileUpload; 

使用這樣的:

app.post('/job/:name', myupload_middleware, function (req, res) { 

我的問題是,現在我得到:

TypeError: Cannot call method 'put' of undefined 

排隊:_this.uploadDelegate.put(file, function (error, storedFile) {

在constructer我看到this.uploadDelegate已設置。 console.log(_this)告訴我這個範圍不是我所期望的範圍?

{ ArrayBuffer: [Function: ArrayBuffer], 
    Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, 
    Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, 
    Uint8ClampedArray: { [Function: Uint8ClampedArray] BYTES_PER_ELEMENT: 1 }, 
    Int16Array: { [Function: Int16Array] BYTES_PER_ELEMENT: 2 }, 
    Uint16Array: { [Function: Uint16Array] BYTES_PER_ELEMENT: 2 }, 
    Int32Array: { [Function: Int32Array] BYTES_PER_ELEMENT: 4 }, 
    Uint32Array: { [Function: Uint32Array] BYTES_PER_ELEMENT: 4 }, 
    Float32Array: { [Function: Float32Array] BYTES_PER_ELEMENT: 4 }, 
    Float64Array: { [Function: Float64Array] BYTES_PER_ELEMENT: 8 }, 
    DataView: [Function: DataView], 
    DTRACE_NET_SERVER_CONNECTION: [Function], 
    DTRACE_NET_STREAM_END: [Function], 
    DTRACE_NET_SOCKET_READ: [Function], 
    DTRACE_NET_SOCKET_WRITE: [Function], 
    DTRACE_HTTP_SERVER_REQUEST: [Function], 
    DTRACE_HTTP_SERVER_RESPONSE: [Function], 
    DTRACE_HTTP_CLIENT_REQUEST: [Function], 
    DTRACE_HTTP_CLIENT_RESPONSE: [Function], 
    COUNTER_NET_SERVER_CONNECTION: [Function], 
    COUNTER_NET_SERVER_CONNECTION_CLOSE: [Function], 
    COUNTER_HTTP_SERVER_REQUEST: [Function], 
    COUNTER_HTTP_SERVER_RESPONSE: [Function], 
    COUNTER_HTTP_CLIENT_REQUEST: [Function], 
    COUNTER_HTTP_CLIENT_RESPONSE: [Function], 
    global: [Circular], 
    process: 
    { title: 'Administrator: Node.js command prompt - node app.js', 
    version: 'v0.10.12', 
    moduleLoadList: 
     [ 'Binding evals', 
     'Binding natives', 
     'NativeModule events', 
     'NativeModule buffer', 
     'Binding buffer', 
     'NativeModule assert', 
     'NativeModule util', 
     'NativeModule path', 
     'NativeModule module', 
     'NativeModule fs', 
     'Binding fs', 
     'Binding constants', 
     'NativeModule stream', 
     'NativeModule _stream_readable', 
     'NativeModule _stream_writable', 
     'NativeModule _stream_duplex', 
     'NativeModule _stream_transform', 
     'NativeModule _stream_passthrough', 
     'NativeModule http', 
     'NativeModule net', 
     'NativeModule timers', 
     'Binding timer_wrap', 
     'NativeModule _linklist', 
     'Binding cares_wrap', 
     'NativeModule url', 
     'NativeModule punycode', 
     'NativeModule querystring', 
     'NativeModule freelist', 
     'Binding http_parser', 
     'NativeModule crypto', 
     'Binding crypto', 
     'NativeModule string_decoder', 
     'NativeModule tty', 
     'Binding tty_wrap', 
     'NativeModule zlib', 
     'Binding zlib', 
     'NativeModule os', 
     'Binding os', 
     'NativeModule console', 
     'Binding signal_wrap', 
     'Binding tcp_wrap', 
     'NativeModule cluster', 
     'NativeModule child_process', 
     'NativeModule dgram', 
     'Binding udp_wrap', 
     'Binding process_wrap' ], 
    versions: 
     { http_parser: '1.0', 
     node: '0.10.12', 
     v8: '3.14.5.9', 
     ares: '1.9.0-DEV', 
     uv: '0.10.11', 
     zlib: '1.2.3', 
     modules: '11', 
     openssl: '1.0.1e' }, 
    arch: 'x64', 
    platform: 'win32', 
    argv: 
     [ 'node', 
     'D:\\GitHub\\unix-node-js-samples\\AzureHelloWorld\\app.js' ], 
    execArgv: [], 
    env: 
     { ALLUSERSPROFILE: 'C:\\ProgramData', 
     AMDAPPSDKROOT: 'C:\\Program Files (x86)\\AMD APP\\', 
     APPDATA: 'C:\\Users\\Administrator\\AppData\\Roaming', 
     CommonProgramFiles: 'C:\\Program Files\\Common Files', 
     'CommonProgramFiles(x86)': 'C:\\Program Files (x86)\\Common Files', 
     CommonProgramW6432: 'C:\\Program Files\\Common Files', 
     COMPUTERNAME: 'SERVER-PC', 
     ComSpec: 'C:\\Windows\\system32\\cmd.exe', 
     FP_NO_HOST_CHECK: 'NO', 
     HOMEDRIVE: 'C:', 
     HOMEPATH: '\\Users\\Administrator', 
     LOCALAPPDATA: 'C:\\Users\\Administrator\\AppData\\Local', 
     LOGONSERVER: '\\\\SERVER-PC', 
     NUMBER_OF_PROCESSORS: '8', 
     OS: 'Windows_NT', 
     Path: 'C:\\Users\\Administrator\\AppData\\Roaming\\npm;C:\\Program Files 
\\nodejs\\;C:\\Program Files (x86)\\AMD APP\\bin\\x86_64;C:\\Program Files (x86) 
\\AMD APP\\bin\\x86;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbe 
m;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files (x86)\\ATI 
Technologies\\ATI.ACE\\Core-Static;C:\\Program Files (x86)\\Microsoft ASP.NET\\A 
SP.NET Web Pages\\v1.0\\;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Bi 
nn\\;C:\\Program Files\\MATLAB\\R2012b\\runtime\\win64;C:\\Program Files\\MATLAB 
\\R2012b\\bin;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\Program 
Files (x86)\\Microsoft SDKs\\TypeScript\\;C:\\Program Files\\nodejs\\;C:\\Users 
\\Administrator\\AppData\\Roaming\\npm', 
     PATHEXT: '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 
     PROCESSOR_ARCHITECTURE: 'AMD64', 
     PROCESSOR_IDENTIFIER: 'Intel64 Family 6 Model 26 Stepping 5, GenuineInte 
l', 
     PROCESSOR_LEVEL: '6', 
     PROCESSOR_REVISION: '1a05', 
     ProgramData: 'C:\\ProgramData', 
     ProgramFiles: 'C:\\Program Files', 
     'ProgramFiles(x86)': 'C:\\Program Files (x86)', 
     ProgramW6432: 'C:\\Program Files', 
     PROMPT: '$P$G', 
     PSModulePath: 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\ 
;C:\\Program Files (x86)\\Microsoft SDKs\\Windows Azure\\PowerShell\\', 
     PUBLIC: 'C:\\Users\\Public', 
     SESSIONNAME: 'Console', 
     SSH_AGENT_PID: '5316', 
     SSH_AUTH_SOCK: '/tmp/ssh-aTYruZ5256/agent.5256', 
     SystemDrive: 'C:', 
     SystemRoot: 'C:\\Windows', 
     TEMP: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\1', 
     TMP: 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\1', 
     USERDOMAIN: 'SERVER-PC', 
     USERDOMAIN_ROAMINGPROFILE: 'SERVER-PC', 
     USERNAME: 'Administrator', 
     USERPROFILE: 'C:\\Users\\Administrator', 
     VS110COMNTOOLS: 'C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\ 
Common7\\Tools\\', 
     windir: 'C:\\Windows' }, 
    pid: 7776, 
    features: 
     { debug: false, 
     uv: true, 
     ipv6: true, 
     tls_npn: true, 
     tls_sni: true, 
     tls: true }, 
    _needImmediateCallback: false, 
    execPath: 'C:\\Program Files\\nodejs\\node.exe', 
    debugPort: 5858, 
    _getActiveRequests: [Function], 
    _getActiveHandles: [Function], 
    _needTickCallback: [Function], 
    reallyExit: [Function], 
    abort: [Function], 
    chdir: [Function], 
    cwd: [Function], 
    umask: [Function], 
    _kill: [Function], 
    _debugProcess: [Function], 
    _debugPause: [Function], 
    _debugEnd: [Function], 
    hrtime: [Function], 
    dlopen: [Function], 
    uptime: [Function], 
    memoryUsage: [Function], 
    binding: [Function], 
    _usingDomains: [Function], 
    _tickInfoBox: { '0': 0, '1': 0, '2': 0 }, 
    _events: { SIGWINCH: [Function] }, 
    domain: null, 
    _maxListeners: 10, 
    EventEmitter: { [Function: EventEmitter] listenerCount: [Function] }, 
    _fatalException: [Function], 
    _exiting: false, 
    assert: [Function], 
    config: { target_defaults: [Object], variables: [Object] }, 
    nextTick: [Function: nextTick], 
    _nextDomainTick: [Function: _nextDomainTick], 
    _tickCallback: [Function: _tickCallback], 
    _tickDomainCallback: [Function: _tickDomainCallback], 
    _tickFromSpinner: [Function: _tickFromSpinner], 
    maxTickDepth: 1000, 
    stdout: [Getter], 
    stderr: [Getter], 
    stdin: [Getter], 
    openStdin: [Function], 
    exit: [Function], 
    kill: [Function], 
    addListener: [Function], 
    on: [Function], 
    removeListener: [Function], 
    mainModule: 
     { id: '.', 
     exports: {}, 
     parent: null, 
     filename: 'D:\\GitHub\\unix-node-js-samples\\AzureHelloWorld\\app.js', 
     loaded: true, 
     children: [Object], 
     paths: [Object] }, 
    _immediateCallback: [Function: processImmediate], 
    _errno: 'EALREADY' }, 
    GLOBAL: [Circular], 
    root: [Circular], 
    Buffer: 
    { [Function: Buffer] 
    isEncoding: [Function], 
    poolSize: 8192, 
    isBuffer: [Function: isBuffer], 
    byteLength: [Function], 
    concat: [Function], 
    _charsWritten: 38 }, 
    setTimeout: [Function], 
    setInterval: [Function], 
    clearTimeout: [Function], 
    clearInterval: [Function], 
    setImmediate: [Function], 
    clearImmediate: [Function], 
    console: [Getter] } 
+0

我會設置一個斷點上的console.log(_this);並看看堆棧跟蹤。它看起來像你的函數被調用apply,call或bind來改變它的含義。也許你可以找出原因。 –

+0

嗨。你有沒有想過爲什麼會發生這種情況。我有同樣的問題。感謝 – Pintac

+0

對不起,很長一段時間,因爲我與它合作,並沒有真正記得。但是,對於這篇文章的回答似乎與我從打字稿中學到的有關。 –

回答

1

使用箭頭功能保留的this意義。

您在這裏用箭頭功能:

async.each(Object.keys(req.files), (field, cb) => { 

如果您不希望保留的this範圍,改爲使用標準功能:

async.each(Object.keys(req.files), function (field, cb) { 

你會看到,編譯後的JavaScript中的_this變量將在您執行此操作時消失。

如果你想兩者的含義,你可以手動存儲上下文...

var _self = this; 
async.each(Object.keys(req.files), function (field, cb) { 
    // self is the "outer this" 
    // this is the "inner this" 
+0

下面是對這個問題的一個很好的解釋,可能的解決方案和權衡考慮:https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript – AronVanAmmers