[英]Use sequentially promise to run some ajax requests in Javascript and jQuery
I have steps array like: 我有类似的步骤数组:
var stepsToDo = [step1, step2, step3,...]
every step does ajax call: ajax调用的每一步:
function step1() { return $.ajax({ ... }); }
function step2() { return $.ajax({ ... }); }
The sample ajax call for step 1
( step 2
and others are similar): step 1
的样本ajax调用( step 2
和其他step 2
相似):
return $.ajax({
url: "test.php",
type: "POST",
dataType: "json",
data: {"step-1": ""},
beforeSend: function () {
writeResult("Processing-> test 1");
},
success: function (result) {
if (result) {
if (result instanceof Array) {
writeResult("Found: " + result.length + " items");
arr = result;
} else {
writeResult(result);
arr = [];
}
}
}
});
function writeResult(str) { console.log(str); }
I want to execute sequentially (defined in stepsToDo). 我想按顺序执行(在stepsToDo中定义)。
I tried like: 我尝试过:
stepsToDo.reduce(
(promise, method) => {
return promise.then(method);
},
Promise.resolve()
);
Nothing happens, no print in console happens. 什么都没有发生,控制台中也没有打印。
Why ? 为什么呢
Drop the new Promise
. 删除new Promise
。 Your steps are functions that return promises, not promise executors - they never would call a resolve
callback passed into them. 您的步骤是返回promise的函数,而不是promise执行器 ,它们永远不会调用传递给它们的resolve
回调。
For the reducer function you initially created... 对于您最初创建的reducer功能...
stepsToDo.reduce((promise, method) => {
return promise.then(_ => new Promise(method));
}, Promise.resolve());
...your step functions should resolve
or reject
the promises created in your reducer - therefore should implement the promise executor signature, IE: ...您的步骤函数应resolve
或reject
您在reducer中创建的promise-因此应实现promise executor签名IE:
type executor = (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void;
For example: 例如:
function step1(resolve, reject) {
$
.ajax({ /* ... */ })
.done(resolve)
.fail(reject);
}
EDIT 编辑
As @Bergi states in the comments, this is an anti-pattern . 正如@Bergi在评论中指出的那样,这是一种反模式 。 Instead you could move the Promise construction into your step functions. 相反,您可以将Promise构造移到您的阶梯函数中。 A basic example (the jQuery ajax API still has to be converted to promises) 一个基本示例(jQuery ajax API仍必须转换为Promise)
function step1() {
return new Promise((resolve, reject) => {
$.ajax({ /* ... */ }).done(resolve).fail(reject);
});
}
If all your steps return you promises your reducer can get much simpler: 如果所有步骤都返回了,您将保证您的减速器可以变得更加简单:
stepsToDo.reduce((promise, method) => promise.then(method), Promise.resolve());
You could in this case even just return the result of $.ajax
, since jQuery promises do implement a then method: 在这种情况下,您甚至可以返回$.ajax
的结果,因为jQuery承诺会实现then方法:
function step1() {
return $.ajax({ /* ... */ });
}
If a native promise is required for error handling, ie Promise.catch
, you can explicitly cast the jQuery promise to a native promise with Promise.resolve
: 如果错误处理需要本机Promise.catch
,即Promise.catch
,则可以使用Promise.resolve
将jQuery Promise.catch
显式转换为本机Promise.resolve
:
function step1() {
return Promise.resolve($.ajax({ /* ... */ }));
}
I'm not sure what's wrong with the other answers but $.get (or ajax or post) will return a promise like. 我不确定其他答案有什么问题,但是$ .get(或ajax或post)会返回类似的承诺。
So your step methods can look like this: 因此,您的步进方法如下所示:
var stepOne = () => {
return $.ajax({//just return the promise like
url: "test.php",
type: "POST",
dataType: "json",
data: {"step-1": ""}
});
}
You can then reduce it to one promise that resolves with the results of the three steps: 然后,您可以将其简化为一个可以解决三个步骤的结果的承诺:
[stepOne,stepTwo,stepThree].reduce(
(p,fn)=>
p.then(
results=>fn().then(result=>results.concat([result]))
),
$.Deferred().resolve([])
)
.then(
results=>console.log("got results:",results),
err=>console.warn("Something went wrong:",err)
);
You see I don't pass Promise.resolve
as second argument to reduce but $.Deferred().resolve([])
, this is jQuery promise like value. 您会看到我没有将Promise.resolve
作为第二个参数传递给reduce,而是$.Deferred().resolve([])
,这是像值一样的jQuery $.Deferred().resolve([])
。 You can now support browsers that don't have native promises without the need to polyfill. 现在,您可以支持没有原生承诺的浏览器,而无需进行polyfill。
Although if you need to support those I'd recomment not using the arrow function syntax and use function(something){return something}
instead of something=>something
尽管如果您需要支持这些功能,我建议您不要使用箭头函数语法,而应使用function(something){return something}
而不是something=>something
There most be something missing from the original question or the implementation. 最初的问题或实现中大部分缺少某些内容。 If all the step functions return the $.ajax
promise then the Array.reduce
pattern should work. 如果所有步骤函数都返回$.ajax
许诺,则Array.reduce
模式应该起作用。
Below is a working prove of concept using a step()
function to simulate the asynchronous code execution and using the exact same Array.reduce
pattern: 下面是使用step()
函数模拟异步代码执行并使用完全相同的Array.reduce
模式的概念的有效证明:
// Step generator function step(number) { return function() { return $.Deferred(function(def) { setTimeout(function() { console.log('Running Step ', number); def.resolve(); }, Math.floor(Math.random() * Math.floor(250))); }).promise(); } } // List of steps var stepsToDo = [step(1), step(2), step(3), step(4), step(5)]; // Consume steps one at a time stepsToDo.reduce( (promise, method) => { return promise.then(method); }, Promise.resolve() ).then(() => console.log('All Done!'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.