简体   繁体   English

使用顺序承诺在Javascript和jQuery中运行一些Ajax请求

[英]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: ...您的步骤函数应resolvereject您在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.

相关问题 在javascript / jquery中按顺序解决Promise - Resolve promise sequentially in javascript/jquery 如何使用Promises顺序发送Javascript / jQuery AJAX POST请求,遍历请求数据数组? - How to send Javascript/jQuery AJAX POST requests sequentially, looping over an array of request data, using Promises? 如何使用jQuery延迟承诺按顺序执行许多任务? - How to use jQuery deferred promise to execute many tasks sequentially? JavaScript:顺序迭代Promise函数 - JavaScript: Sequentially iterate promise function jQuery的/ JavaScript的:如何顺序(而不是并行)加载(一些)图像? - jquery/javascript: how to load (some) images sequentially rather than in parallel? 在Javascript中使用Promise调用JQuery Ajax函数 - Using Promise in Javascript to Call the Function JQuery Ajax Ajax Promise在同一时间而不是顺序执行 - Ajax promise is executed in same time instead of sequentially 如何使用在等待下一个Prom之前等待jquery ajax完成的JavaScript Promise? - How to use javascript promises that waits for jquery ajax to finish before moving onto next promise? 如何按顺序处理一系列AJAX请求的结果? - How to process the results of a series of AJAX requests sequentially? Javascript,jQuery同时处理多个AJAX请求 - Javascript, jQuery multiple AJAX requests at same time
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM