2016-10-12 11 views
2

JavaScriptで以下のタスクをどのように処理できるか少し助けてください: 私は画像処理とノードスプライトジェネレータにJimp を使用するアプリを持っています。これはすべてnode.jsコンテキストで実行されます。私はJimpにいくつかの画像をロードし、画像で何かを作ってから、nodejsファイルモジュールを使ってファイルシステムに書き戻します。その後、私は新しい作成された画像を取り出し、それをノードスプライトジェネレータに貼り付けました。問題は、現時点ではすべての画像が作成/書き出されるわけではないということです。 Jimpが返った直後にスプライトシートを作成するコードが実行されますが、Jimpはすべての画像を処理して約束を返すと思います。その結果、スプライトシートを作成するコードは実行されますが、スタックは実行されません。ファイルがnode.jsで完全に書き込まれていることを確認してください

私は(fs.statと、ファイルが書き込まれているかどうかをテストしてみました)と

if (stat.mtime.getTime() === prev.mtime.getTime()) 

ようpropertieのmtimeしかし、ファイルがで作成されていない場合、エラーが発生したこと、起こることができます今回。また、画像へのパスが現在利用できないときに、画像が完全に処理されているかどうかを確認する方法が必要です。

function resize(img) { 
    Jimp.read(img.path).then(function (err, file) { 
     if (err) throw err; 
     file.resize(200, 200) 
      .quality(70) 
      .write(newPath); //newPath for simplicity 
    }); 
} 


function rec(imgObjArray) { 
    if(_.isEmpty(imgObjArray)) return; 
    resize(imgObjArray.pop()); 
//correct mistake in function call from fn() to rec() 
    rec(imgObjArray); 
} 

rec(imgObjArray); //imgObjArray === [img,img,img....] 

//nsg() does not work because not all images are written at this time 
    nsg({ 
      src: [ 
       'out/images/desktop/*.jpg' 
      ], 
      spritePath: 'out/images/desktop/sprite.jpg',, 
      compositor: 'jimp' 
     }, function (err) { 
      console.log('Sprite generated!'); 
     }) 

まず、イメージが特定のパスに存在するかどうかを確認し、書き込みが完了しているかどうかを確認する必要があります。しかし、fs.access(path [、mode]、callback)を使ってfnを作成し、この時点でファイルが作成されていないときは、エラーが発生します。

+0

もしあなたが約束を持っていたら、最初のアクションが実行されたときに次のアクションを実行するためにそれを使用する必要があります。コードを修正する方法に関する有用なガイダンスを提供するために、コードを、またはタスクの移行先の少なくとも一部に見ておくと便利です。 – Jason

+0

私もそう思ったので、スプライトシートコードを実行するfn-callを含むjimpキューにthen()関数を作成します。しかし、私は同じ問題を抱えています。 – Zantinger

+0

コードを表示する必要があります。コードに関する質問は、あなたの質問に関連するコードを含まなければなりません。コードを表示すると数分で助けてくれるかもしれません。 – jfriend00

答えて

2

同期コードと非同期コードが混在しています。私はコメントで何が起こっているかを説明しようとするでしょう:

まず、あなたの関数の定義 - あなたが適切

// I've re-spaced the code slightly and removed your comments so mine stand out 
function resize(img) { 
    Jimp.read(img.path).then(function (err, file) { 
     // this code only executes after the file is done reading, but this 
     // is an asynchronous action - it doesn't hold up execution 
     if (err) throw err; 
     file.resize(200, 200).quality(70).write(newPath); 
     // .write() is presumably *also* an asynchronous action - if you want 
     // something to happen only *after* it's been written, it needs to be in 
     // a callback or promise on the write method 
    }); 

    // I added this explicitly - after you *start* your Jimp.read, you *immediately* 
    // return from this function, *before* the read is completed. If you want 
    // something to happen only *after* your read and write, you either need to 
    // return the promise so you can act on it, or put the further actions in a callback 
    return undefined; 
} 

function rec(imgObjArray) { 
    if(_.isEmpty(imgObjArray)) return; 
    // resize() runs and returns *before* the file is read, resized, and written 
    resize(imgObjArray.pop()); 
    // I don't know what fn() is, it's not defined here - presumably it's not important 
    fn(imgObjArray); 
} 

...そして、あなたの手続きの呼び出しを自分の補完を処理せずに、非同期アクションをオフに発射している:

// this fires off and completes immediately, having initiated the asynchronous methods 
rec(imgObjArray); 

// you call this on the assumption that all of your code above has completed, but since 
// it's asynchronous, that's not true, you get here with *none* of your images completed 
nsg({ 
    src: [ 
     'out/images/desktop/*.jpg' 
    ], 
    spritePath: 'out/images/desktop/sprite.jpg', 
    compositor: 'jimp' 
}, function (err) { 
    console.log('Sprite generated!'); 
}); 

あなたは2つのオプションがあります。file.write()は同期呼び出しで、あなただけの私に約束と行動を返すことができる場合

をT:約束の構文が正しくない場合

function resize(img) { 
    // by *returning* this call, we're actually returning the promise, we can act on 
    // in the future 
    return Jimp.read(img.path).then(function (err, file) { 
     if (err) throw err; 
     file.resize(200, 200).quality(70).write(newPath); 
    }); 
} 

function rec(imgObjArray) { 
    if(_.isEmpty(imgObjArray)) return; 
    // the result of resize is now a promise 
    return resize(imgObjArray.pop()).then(function(err) {; 
     // again, assuming `fn()` is synchronous... 
     fn(imgObjArray); 
    }); 
} 

// now the result of *this* call is a promise, which you can use to control 
// the timing of your next call 
rec(imgObjArray).then(function(err) { 
    // now this will only run after all of the previous calls have executed 
    nsg({ 
     src: [ 
      'out/images/desktop/*.jpg' 
     ], 
     spritePath: 'out/images/desktop/sprite.jpg', 
     compositor: 'jimp' 
    }, function (err) { 
     console.log('Sprite generated!'); 
    }); 
}); 

...謝罪、私は彼らがユビキタスになった積極ので、ノードを使用していません。

サブコールが非同期であっても、同じ方法で約束を使用する方法がありますが、私はそれを準備していません。

そうでない場合、あなたはあなたの関数にコールバックを渡すことができます。

function resize(img, cb) { 
    // ... you get the idea... 
     file.resize(200, 300).quality(70).write(newPath, cb); 
} 

function rec(imgObjArray, cb) { 
    // ... you get the idea... 
    resize(imgObjArray.pop(), cb); 
} 

rec(imgObjArray, function(err, response) { 
    nsg({ 
     src: [ 
      'out/images/desktop/*.jpg' 
     ], 
     spritePath: 'out/images/desktop/sprite.jpg', 
     compositor: 'jimp' 
    }, function (err) { 
     console.log('Sprite generated!'); 
    }); 
}); 

は、この情報がお役に立てば幸い!

+0

IT制作!あまりにも@ Jasonありがとうございます。PS:fn()関数は実際のrec()呼び出しです。これは配列imgObjが空になるまで関数自身を呼び出します。しかし、最も重要なことは、あなたが働いている解決策で私を助けてくれることです。ありがとう。 – Zantinger

+0

他のアドバイス - 再帰呼び出しは配列をループするだけでは効率的ではないので、 'rec()'関数はそれ自身を呼び出して要素をポップするのではなく、単純なループを行う必要があります。あなたのスコープが設定されると、最終結果は同じになります。いずれにせよ、私はこれが助けてうれしいです! – Jason

関連する問題