你怎么知道一个无限长的承诺链什么时候完成了?

jfr*_*d00 5 javascript asynchronous promise

我试图使用promises强制序列化一系列Ajax调用.每次用户按下按钮时,这些Ajax调用都会成为一个.我可以成功地序列化这样的操作:

// sample async function
// real-world this is an Ajax call
function delay(val) {
    log("start: ", val);
    return new Promise(function(resolve)  {
        setTimeout(function() {
            log("end: ", val); 
            resolve();
        }, 500);
    });
}

// initialize p to a resolved promise
var p = Promise.resolve();
var v = 1;

// each click adds a new task to 
// the serially executed queue
$("#run").click(function() {
    // How to detect here that there are no other unresolved .then()
    // handlers on the current value of p?
    p = p.then(function() {
        return delay(v++);
    });
});
Run Code Online (Sandbox Code Playgroud)

工作演示:http://jsfiddle.net/jfriend00/4hfyahs3/

但是,这构建了一个可能永无止境的承诺链,因为p永远不会清除存储最后一个承诺的变量.每一项新业务都只是扼杀了先前的承诺.所以,我认为为了良好的内存管理,我应该能够检测到什么时候没有.then()剩余的处理程序继续运行当前值,p然后我可以重置值p,确保前一个链的任何对象承诺处理程序可能已关闭,将有资格进行垃圾回收.

所以,我想知道如何在给定的.then()处理程序中知道在.then()这个链中没有更多的处理程序被调用,因此,我可以做到p = Promise.resolve()重置p并释放先前的promise链而不是不断添加到它上面.

mxd*_*ois -1

您可以将承诺推入数组并使用Promise.all

var p = Promise.resolve, 
   promiseArray = [], 
   allFinishedPromise;

function cleanup(promise, resolvedValue) {
    // You have to do this funkiness to check if more promises
    // were pushed since you registered the callback, though.
    var wereMorePromisesPushed = allFinishedPromise !== promise;
    if (!wereMorePromisesPushed) {
        // do cleanup
        promiseArray.splice(0, promiseArray.length);
        p = Promise.resolve(); // reset promise
    }
}

$("#run").click(function() {
    p = p.then(function() {
        return delay(v++);
    });
    promiseArray.push(p)
    allFinishedPromise = Promise.all(promiseArray);
    allFinishedPromise.then(cleanup.bind(null, allFinishedPromise));
});
Run Code Online (Sandbox Code Playgroud)

或者,由于您知道它们是按顺序执行的,因此您可以让每个完成回调从数组中删除该承诺,并在数组为空时重置承诺。

var p = Promise.resolve(), 
    promiseArray = [];

function onPromiseComplete() {
    promiseArray.shift();
    if (!promiseArray.length) {
        p = Promise.resolve();
    }
}

$("#run").click(function() {
    p = p.then(function() {
        onPromiseComplete();
        return delay(v++);
    });
    promiseArray.push(p);
});
Run Code Online (Sandbox Code Playgroud)

编辑:如果数组可能会变得很长,那么您应该选择第一个选项 b/c,移动数组的时间复杂度为 O(N)。

编辑:正如您所指出的,没有理由保留阵列。计数器就可以正常工作。

var p = Promise.resolve(), 
    promiseCounter = 0;

function onPromiseComplete() {
    promiseCounter--;
    if (!promiseCounter) {
        p = Promise.resolve();
    }
}

$("#run").click(function() {
    p = p.then(function() {
        onPromiseComplete();
        return delay(v++);
    });
    promiseCounter++;
});
Run Code Online (Sandbox Code Playgroud)