在我解释要做什么之前,这是我正在编码的MCV
for c_file in /dir1/*.fa; do
b_file=/dir2/$(basename "$c_file" .fa).rem
echo "$c_file" "$b_file"
done
因此,我有一个文本区域,其中包含未知数量的BLOB对象。我首先尝试使用regexp查找这些BLOB对象,然后使用一个名为uploader.php的PHP文件将它们上传到服务器。文件上传后,它将返回上传文件的URL,我想用文本区域中上传文件的URL替换BLOB URL,然后将文本区的最终内容提交给服务器以进行进一步处理。
事实证明,当我运行代码时,仅将regexp的最后一个实例替换为其上载的URL。其他人保持原样。我怀疑这是因为while循环不会等待ajax请求完成。尝试提交表单时,我遇到了类似的问题,我按照此answer中的建议解决了问题,但这次我不知道如何解决此问题。
任何想法都值得赞赏
更新:我试图使ajax同步工作,但是我的浏览器说它已被弃用,并且不起作用。
答案 0 :(得分:1)
所以。我在评论中说,您可以使用async / await,并提供链接。现在,我将尝试教您如何使用Promise和XMLHttpRequest。
第一件事。我会使用自己的名为PromiseReq的“库”(不是真正的库,只是3个新命令),它具有返回Promises的XMLHttpsRequest。
您将需要两个功能:
sendToServer(config, data)
和getServerFile(config)
。它们按照其名称的含义进行操作。(sendToServer
当时还不太好,但是稍后我会进行改进)。他们只是使用Promises作为回报。他们以非常简单的方式工作。 Code @ Github
但是它仅为我使用而设计,因此它不是非常灵活(尽管我希望我会在某个时候加以改进)。
所以我们需要学习如何使用Promises。
首先,您需要了解Promise是什么以及我们为什么使用它。
然后您可以创建一个这样的文件:
let pmq = new Promise((res,rej)=>{
// PROMISE BODY HERE
});
这里是第一个警告。以这种方式做出的承诺不支持将退货作为解决Promise的一种方式!您必须使用res()
!
某些函数只是返回它们(例如fetch()),我们可以在调用函数后立即处理它们。
现在pmq
是我们的承诺。
您可以使用pmq.then(callback)
处理在res()
调用诺言主体中某处时将发生的情况,并且可以使用pmq.catch(callback)
处理在调用rej()
时发生的情况。请记住,.catch(cb)
和.then(cb)
返回一个Promise,因此您可以安全地链接多个.then()
,最后添加.catch()
,它将处理来自每个.then()
。
例如:
pmq = fetch("file.txt");
pmq.then(e=>console.log(e.json())).then(console.log).catch(console.error);
那里有一个大音符。
此事件的触发顺序。
例如,如果rP()
比日志"A"
等待1秒然后解析,则此代码:
let a = rP();
a.then(_=>console.log("B")).catch(console.error);
console.log("C");
将导致:
C
A
B
为此,需要async/await来完成此操作。
为此,您必须使用关键字async
创建一个异步函数。
let fn = async ()=>{}
这是第二件事。异步函数总是返回Promise。这是您创造承诺的第二种方式。您只是不只使用res()
和rej()
来使用return
,throw
。
现在我们可以在fn()
内部进行呼叫:
let a = await rP().then(_=>console.log("B")).catch(console.error);
console.log("C");
我们将得到我们的
A
B
C
现在。如何与XMLHttpRequest一起使用?
您需要使用简单的XMLHttpRequest创建新的Promise:
let xmlp = (type, path,data) => return new Promise((res,req)=>{
let xhr = new XMLHttpsRequest();
xhr.open(type, path, true); // true implies that is it asynchronous call
//...
xhr.send(data);
});
现在什么时候解决?
XMLHttpRequest
具有有用的event properties and events。最适合我们的情况的是onreadystatechange
。
您可以像这样使用它:
xhr.onreadystatechange = _=>{
if(xhr.readyState === 4 && xhr.status === 200) // Everything went smoothly
res(xhr.responseText);
else if(shr.readyState === 4 && xhr.status !== 200) // Something went wrong!
rej(xhr.status);
}
然后要获取数据,您可以
Async/Await
// INSIDE ASYNC FUNCTION
let resData = await xmpl("GET", "path.txt", null).catch(console.error);
.then()
let resData;
xmpl("GET", "path.txt", null).then(r=>{
resData = r;
// REST OF WHOLE FUNCTION TO ENSURE THAT resData HAS BEEN SET
})
.catch(console.error);
您还可以使用xmpl()
发送数据。
xmpl("POST", "observer.php", "Data to send to observer.php!")
.then(whatToDoAfterSendFN);
/*
to get such data in PHP you have to use
$post = file_get_contents('php://input');
*/
我知道这个答案有点杂乱无章,但是我不知道该怎么写:P对不起。
答案 1 :(得分:1)
似乎您并不需要同步(我看不到最好让异步动作看起来是同步的情况),而只需要顺序即可。
可以通过使用回调(可重写为Promise,然后可重写为async / await方法,使回调顺序执行),
// myString is made global for simplicity
var myString;
function uploadBlob(myBlob, addr, callback) {
var data = new FormData();
data.append('file', myBlob);
$.ajax({
url: "uploader.php",
type: 'POST',
data: data,
contentType: false,
processData: false,
success: function(data) {
// file uploaded OK, replace the blob expr by the uploaded file url(data)
myString = myString.replace("blob:" + addr, data);
callback();
},
error: function() {
// error, the uploaded most likely failed, we leave myString alone
// or alternatively replace the blob expr by empty string
// because maybe we dont want to post blob in the final form submit
// uncomment if needed
// myString = myString.replace("blob:" + addr, "");
callback();
}
});
}
function getBlobAndUpload(addr, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:' + addr, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var myBlob = this.response;
uploadBlob(myBlob, addr, callback);
} else {
// error, but callback anyway to continue processing
callback();
}
};
xhr.send();
}
function processAddresses(addresses, callback, current) {
var index = current || 0;
// all addresses processed?
if (index >= addresses.length) {
// yes no more address, call the callback function
callback();
} else {
var addr = addresses[index];
// once the get/upload is done the next address will be processed
getBlobAndUpload(addr, function() {
processAddresses(addresses, callback, index + 1);
});
}
}
$("#button").submit(function(event) {
event.preventDefault();
var formData = new FormData(this);
var addresses = [];
// initialize both localString and myString to the content of the textArea
// localString will be used to extract addresses,
// while myString will be mutated during the upload process
var localString = myString = $('#textarea').val();
var myRegexp = /src="blob:([^'"]+)"/gm;
match = myRegexp.exec(localString);
// collect all addresses first
while (match != null) {
addr = match[1];
addresses.push(addr);
match = myRegexp.exec(localString);
}
// initiate sequential processing of all addresses, and
// pass the callback function triggering the form submit
processAddresses(addresses, function() {
// all the successfully uploaded blob exprs in my string should
// be now replaced by the remote file url now (see commented part
// in upload blob error for a variation of the feature
formData.set('textarea', myString);
submitForm(formData);
});
});