2016-10-12 4 views
2

Мне нужно немного помочь, как я могу справиться с следующей задачей в JavaScript: У меня есть приложение, которое использует Jimp для обработки изображений и генератора узлов-спрайтов. Это все работает в контексте node.js. Я загружаю несколько изображений в Jimp, делаю что-то с изображением, а затем записываю его обратно в свою файловую систему с помощью файла nodejs filemodule. Затем я бы взял новые созданные изображения и вставил их в узел-спрайт-генератор. Проблема в том, что не все изображения создаются/записываются в это время. Хотя код для создания спрайтов запускается сразу же после возвращения Jimp, я думаю, что Jimp обрабатывает все изображения и возвращает обещание. В результате создается код для создания спрайта, но стек не выполняется.Проверьте, полностью ли написан файл с node.js

Я пытался проверить, если файл записывается с fs.stat() и СВОЙСТВ как

время изменения
if (stat.mtime.getTime() === prev.mtime.getTime()) 

Но тогда это может случится, что произошла ошибка, когда файл не создается в в этот раз. Кроме того: мне нужен способ проверить, полностью ли написано изображение с обработкой, когда путь к изображению в настоящее время недоступен.

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!'); 
     }) 

Я думаю, что сначала я должен проверить, существует ли изображение по заданному пути, а затем проверить, завершена ли запись. Но когда я делаю fn с fs.access (путь [, режим], обратный вызов), и файл не создается в это время, я получаю сообщение об ошибке.

+0

Если у вас есть обещание, вам нужно использовать его для выполнения следующего действия, когда первый будет выполнен. Было бы полезно увидеть ваш код или, по крайней мере, часть его, где вы выполняете задачи, для предоставления каких-либо полезных рекомендаций по его устранению. – Jason

+0

Я тоже так думал, поэтому я делаю функцию then() для очереди jimp, которая содержит fn-call для выполнения кода спрайт-листа. Но у меня такая же проблема. – 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!'); 
}); 

у вас есть два варианта:

Если file.write() является синхронным вызовом, вы можете просто вернуть обещание и действовать на I т:

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

ЭТО РАБОТАЕТ! Большое вам спасибо @ Джейсон.PS: функция fn() является фактическим вызовом rec(). Это вызовет функцию непосредственно до тех пор, пока массив imgObj не будет пустым. Но самое главное, что вы помогаете мне с рабочим решением. Благодарю. – Zantinger

+0

ОК, так что еще один совет - рекурсивные вызовы менее эффективны, чем просто цикл по массиву, поэтому ваша функция 'rec()' должна просто выполнять простой цикл, а не вызывать себя и выскакивать элементы. С учетом того, что он настроен, конечный результат будет таким же. В любом случае, я рад, что это помогло! – Jason