承诺,然后绑定问题

Promise.then bind issue

本文关键字:问题 绑定 然后 承诺      更新时间:2023-09-26

我一直面临着将值绑定到下一个 Promise 的问题。看看下面的代码,它会更好地解释情况。

'use strict';
function FindEvent(eventId) {
    console.log('Event:', eventId);
    return Promise.resolve({title: 'MyEvent'});
}
function FindUser(userId) {
    console.log('User:', userId);
    return Promise.resolve({username: 'MyUser'});
}
function MyServiceProblem(payload) {
    payload.userId = 'blah';
    return FindEvent(payload.eventId)
        .then((event) => {
            payload.userId = 'test';
            // setting a breakpoint here shows
            // that the value to payload.userId has been
            // assigned, i.e. 'test'
            return Promise.resolve(payload);
        })
        .then(FindUser.bind(this, payload.userId));
        // But new value doesn't reaches inside FindUser
}
MyServiceProblem({ // userId is 'blah', why not 'test'
    eventId: '456'
});
function MyServiceWorks(payload) {
    payload.userId = 'blah';
    return new Promise((resolve) => {
        payload.userId = 'test';
        return resolve(payload);
    })
        .then(FindUser.bind(this, payload.userId));
        // From here, the 'test' value reaches FindUser
}
MyServiceWorks({ // userId is 'test'
    eventId: '456'
});

问题是,为什么它绑定的值对于这两种情况都是不同的。两者都完全相同,除了这个是首先解决承诺的部分,然后给payload.userId赋值。

让我们稍微

分解一下你的代码。你有

function MyServiceProblem(payload) {
    payload.userId = 'blah';
    return FindEvent(payload.eventId)
        .then((event) => {
            payload.userId = 'test';
            return Promise.resolve(payload);
        })
        .then(FindUser.bind(this, payload.userId));
}

问题是您的.bind将在您的回调之前运行。此代码也可以编写为

function MyServiceProblem(payload) {
    payload.userId = 'blah';
    var firstThenCallback = (event) => {
        payload.userId = 'test';
        return Promise.resolve(payload);
    };
    var secondThenCallback = FindUser.bind(this, payload.userId);
    return FindEvent(payload.eventId)
        .then(firstThenCallback)
        .then(secondThenCallback);
}

payload对象在所有对象之间共享,但payload.userIdfirstThenCallback有机会执行之前就传递到.bind中。

而不是使用 .bind 并立即传递值,似乎最简单的解决方案是使用匿名函数,以便稍后只读取userId值。

function MyServiceProblem(payload) {
    payload.userId = 'blah';
    return FindEvent(payload.eventId)
        .then((event) => {
            payload.userId = 'test';
            return Promise.resolve(payload);
        })
        .then(() => FindUser(payload.userId));
}

也完全不清楚你为什么要写这么迂回的承诺代码,但我认为这是一个精简的例子?为什么要用payload解决,而不仅仅是在该函数中调用FindUser,例如

function MyServiceProblem(payload) {
    payload.userId = 'blah';
    return FindEvent(payload.eventId)
        .then((event) => {
            payload.userId = 'test';
            return FindUser(payload.userId);
        });
}