525 Stimmen

Wie kann ich auf Promise-Auflösungsrückrufe außerhalb des Scope des Promise-Constructor-Rückrufs zugreifen?

Normalerweise wird ein Promise konstruiert und wie folgt verwendet:

new Promise((resolve, reject) => {
  const obj = new MyEventEmitter();
  obj.onsuccess = (event) => { resolve(event.result); };
  obj.onerror = (event) => { reject(event.error); };
});

Aber in letzter Zeit habe ich etwas Ähnliches wie das folgende gemacht, um den Resolver außerhalb des Executor-Callbacks flexibler zu handhaben:

let outsideResolve;
let outsideReject;
new Promise((resolve, reject) => {
  outsideResolve = resolve; 
  outsideReject = reject; 
});

Und später:

onClick = function() {
  outsideResolve();
}

Dies funktioniert gut, aber gibt es einen einfacheren Weg, dies zu tun? Wenn nicht, ist dies eine gute Praxis?

21voto

Ali Punkte 2279

Akzeptierte Antwort ist falsch. Es ist ziemlich einfach mit Scope und Referenzen zu arbeiten, obwohl es die Promise Puristen wütend machen kann:

const createPromise = () => {
    let resolver;
    return [
        new Promise((resolve, reject) => {
            resolver = resolve;
        }),
        resolver,
    ];
};

const [ promise, resolver ] = createPromise();
promise.then(value => console.log(value));
setTimeout(() => resolver('foo'), 1000);

Im Wesentlichen erfassen wir die Referenz auf die Auflösefunktion, wenn das Versprechen erstellt wird, und geben diese zurück, damit sie extern festgelegt werden kann.

In einer Sekunde wird die Konsole ausgeben:

> foo

16voto

Michal Filip Punkte 900

Nur für den Fall, dass jemand nach einer TypeScript-Version eines Hilfsprogramms sucht, um diese Aufgabe zu vereinfachen:

export const deferred = () => {
  let resolve!: (value: T | PromiseLike) => void;
  let reject!: (reason?: unknown) => void;
  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  return { resolve, reject, promise };
};

Dies kann z.B. verwendet werden wie:

const { promise, resolve } = deferred();

promise.then((value) => console.log(value)); // nichts

resolve('foo'); // Ausgabe: foo

15voto

Cory Danielson Punkte 13816

Eine Hilfsmethode würde diesen zusätzlichen Overhead beseitigen und Ihnen das gleiche jQuery-Gefühl geben.

 ` function Deferred () {
    lassen Sie die Auflösung;
    lassen Sie den verweigern;
    const Versprechen = neue Promise ((res, rej) => {
        lösen Sie = res;
        verweigern = rej;
    });
    return {Versprechen, lösen, verweigern};
}
` 

Verwendung wäre

 ` const {promise, resolve, reject} = Deferred ();
displayConfirmationDialog ({
    bestätigen: lösen,
    stornieren: ablehnen
});
return Versprechen;
` 

Was ähnlich ist wie jQuery

 ` const dfd = $.Deferred ();
displayConfirmationDialog ({
    bestätigen: dfd auflösen,
    stornieren: dfd ablehnen
});
return dfd.promise();
` 

Obwohl, in einem Anwendungsfall ist diese einfache natürliche Syntax in Ordnung

 ` return new Promise ((auflösen, ablehnen) => {
    displayConfirmationDialog ({
        bestätigen: lösen,
        stornieren: ablehnen
    });
});
`

13voto

Arik Punkte 4553

Ich verwende eine Hilfsfunktion, um das zu erstellen, was ich einen "flachen Promise" nenne -

function flatPromise() {

    let resolve, reject;

    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });

    return { promise, resolve, reject };
}

Und ich verwende es wie folgt -

function doSomethingAsync() {

    // Holen Sie sich Ihren Promise und Callbacks
    const { resolve, reject, promise } = flatPromise();

    // Mach etwas Erstaunliches...
    setTimeout(() => {
        resolve('fertig!');
    }, 500);

    // Geben Sie Ihren Promise an die Welt weiter
    return promise;

}

Vollständiges Arbeitsbeispiel anzeigen -

function flatPromise() {

    let resolve, reject;

    const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });

    return { promise, resolve, reject };
}

function doSomethingAsync() {

    // Holen Sie sich Ihren Promise und Callbacks
    const { resolve, reject, promise } = flatPromise();

    // Mach etwas Erstaunliches...
    setTimeout(() => {
        resolve('fertig!');
    }, 500);

    // Geben Sie Ihren Promise an die Welt weiter
    return promise;
}

(async function run() {

    const result = await doSomethingAsync()
        .catch(err => console.error('abgelehnt mit', err));
    console.log(result);

})();

Bearbeiten: Ich habe ein NPM-Paket namens flat-promise erstellt und der Code ist auch auf GitHub verfügbar.

12voto

Hinrich Punkte 12847

Sie können das Promise in einer Klasse einpacken.

class Deferred {
    constructor(handler) {
        this.promise = new Promise((resolve, reject) => {
            this.reject = reject;
            this.resolve = resolve;
            handler(resolve, reject);
        });

        this.promise.resolve = this.resolve;
        this.promise.reject = this.reject;

        return this.promise;
    }
    promise;
    resolve;
    reject;
}

// So wird es verwendet.
const promise = new Deferred((resolve, reject) => {
  // Verwendung wie bei normalen Promise.
});

promise.resolve(); // Resolve von jedem Kontext aus.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X