我有一个类似于这篇博客文章所描述的情况:使用 Promises 进行轮询。作者描述了如何使用 Promises 进行轮询,直到返回 JobID。我想使用 Q 来转换它。
我很乐意发布代码作为起点,但我不确定该发布什么。理想情况下,我正在尝试将 Promises 链接在一起。我一直在尝试使用 Q.delay(),但它似乎无法实现我的目标。
我很乐意发布代码作为起点,但我不确定该发布什么。理想情况下,我正在尝试将 Promises 链接在一起。我一直在尝试使用 Q.delay(),但它似乎无法实现我的目标。
var promise = uploadFile();
promise.then(startImageProcessingJob)
.then(saveConvertedImage);
请提供有关如何创建一个promise的建议,该promise将继续轮询直到检索到数据(或达到最大尝试次数)。
以下是作者使用bluebird的代码。
var getJobStatusAsync = Promise.promisifyAll(api);
function poll(jobId, retry) {
if(!retry) retry = 5;
if(!retry--) throw new Error('Too many retries');
return getJobStatusAsync(jobId)
.then(function(data) {
if(data.state === 'error') throw new Error(data.error);
if(data.state === 'finished') return data;
return Promise.delay(jobId, 10000).then(poll);
});
编辑:
针对Traktor53的评论,我正在添加我已经完成的逻辑。我试图避免添加额外的代码来使问题变得臃肿。
目标:
在我的Angular应用程序中,我想使用ZamZar第三方服务将图像转换为PNG格式。我的设计实现是使用promises来:
(1) 从客户端上传文件到服务器(Node);
(2) 使用ZamZar API启动图像转换(获取JobID);
(3) 使用JobID,轮询ZamZar API以获取状态更新,直到图像准备好下载。一旦图像准备好,我就可以获取fileId并将文件下载回Node服务器。
(4) 一旦PNG图像回到我的服务器上,我想将图像返回给客户端浏览器并放入HTML画布中(使用three.js和fabric.js)。
/* Dependencies */
var express = require('express');
var request = require('request');
var formidable = require('formidable');
var randomstring = require("randomstring");
var fs = require('fs');
var Q = require('q');
/*
* Helper functions in Node
*/
convertFileUtil = function() {
/**
* Step 1: upload file from client to node server.
* formidable is used for file upload management. This means the file is
* automatically uploaded to a temp directory. We are going to move the
* uploaded file to our own temp directory for processing.
* Return Type: A Promise is returned with payload containing the directory
* path for the image file. This path is referenced in subsequent chained methods.
*/
var uploadFileFromClientToNodeServer = function(req) {
var q = Q.defer();
var form = new formidable.IncomingForm();
var tmpFolder = 'upload/' + randomstring.generate() + '/';
//Use formidable to parse the file upload.
form.parse(req, function(err, fields, files) {
if (err) {
console.log(err);
throw err;
}
//When upload is successful, create a temp directory and MOVE file there.
//Again, file is already uploaded. There is no need to use fs.writeFile* methods.
mkdirp(tmpFolder, function (err) {
if (err) {
q.reject(err);
} else {
//File will be saved here.
var tmpFileSavedLocation = tmpFolder + files.file.name;
//Call fs.rename to MOVE file from formidable temp directory to our temp directory.
fs.rename(files.file.path, tmpFileSavedLocation, function (err) {
if (err) {
q.reject(err);
}
console.log('File saved to directory:', tmpFileSavedLocation);
q.resolve(tmpFileSavedLocation);
});
}
});
});
return q.promise;
};
/**
* Step 2: Post the temp file to zam zar. ZamZar is an API service that converts
* images to a different file format. For example, when a user uploads an Adobe
* Illustrator EPS file; the file is sent to zamzar for conversion to a PNG. all
* image formats are returned as PNG which will be added to the canvas.
* Return: This promise will return the JobID of our submission. The JobID will be
* used in subsequent promise to retrieve the converted image.
*/
var postTempFileToZamZar = function(filePath) {
console.log('FilePath', filePath);
var q = Q.defer();
var formData = {
target_format: 'png',
source_file: fs.createReadStream(filePath),
};
//console.log('OK', formData);
//Send file to zamzar for conversion.
request.post({ url: 'https://sandbox.zamzar.com/v1/jobs/', formData: formData }, function (err, response, body) {
if (err) {
console.log('An error occurred', err);
q.reject(err);
} else {
var jsonData = JSON.parse(body);
console.log('SUCCESS! Conversion job started:', jsonData.id);
//This object will be returned in promise payload.
var returnObj = {
filePath: filePath,
jobId: jsonData.id,
};
console.log('Process complete. Returning: ', returnObj);
q.resolve(returnObj);
return q.promise;
}
}).auth(zamzarApiKey, '', true);
};
/*
* Step 3: Poll for PNG.
*/
var pollZamZarForOurPngFile = function(dataObj) {
console.log('pollZamZarForOurPngFile', dataObj);
}
//API
return {
uploadFileFromClientToNodeServer: uploadFileFromClientToNodeServer,
postTempFileToZamZar: postTempFileToZamZar,
pollZamZarForOurPngFile: pollZamZarForOurPngFile,
};
};
//Call to convert file.
app.post('/convertFile', function (req, res) {
var util = convertFileUtil();
//Get file data.
var promise = util.uploadFileFromClientToNodeServer(req);
promise
.then(util.postTempFileToZamZar)
.then(util.pollZamZarForOurPngFile);
.then(function(data) {
console.log('Done processing');
});
});
retry
将始终未定义,并且轮询的第一行将始终将其设置为 5,因此这将永远重试。 2 - 即使 retry 被反馈到轮询中,当它达到 0 时,轮询中的第一行也会将其重置为 5,因此下一行永远不会成立。 - Jaromanda Xdata.state
的字符串值。你能告诉我们可能是什么吗?您如何设想startImageProcessingJob
目标函数会遇到此状态。 - traktor