Bir vanilya ECMAScript 6 Söz zincirini iptal edin


110

.thenBir JavaScript’in ’lerini temizlemek için bir yöntem var mıPromise örneğinin ' ?

QUnit'in üstüne bir JavaScript test çerçevesi yazdım . Çerçeve, her birini bir Promise. (Bu kod bloğunun uzunluğu için özür dilerim. Elimden geldiğince yorum yaptım, bu yüzden daha az sıkıcı geliyor.)

/* Promise extension -- used for easily making an async step with a
       timeout without the Promise knowing anything about the function 
       it's waiting on */
$$.extend(Promise, {
    asyncTimeout: function (timeToLive, errorMessage) {
        var error = new Error(errorMessage || "Operation timed out.");
        var res, // resolve()
            rej, // reject()
            t,   // timeout instance
            rst, // reset timeout function
            p,   // the promise instance
            at;  // the returned asyncTimeout instance

        function createTimeout(reject, tempTtl) {
            return setTimeout(function () {
                // triggers a timeout event on the asyncTimeout object so that,
                // if we want, we can do stuff outside of a .catch() block
                // (may not be needed?)
                $$(at).trigger("timeout");

                reject(error);
            }, tempTtl || timeToLive);
        }

        p = new Promise(function (resolve, reject) {
            if (timeToLive != -1) {
                t = createTimeout(reject);

                // reset function -- allows a one-time timeout different
                //    from the one original specified
                rst = function (tempTtl) {
                    clearTimeout(t);
                    t = createTimeout(reject, tempTtl);
                }
            } else {
                // timeToLive = -1 -- allow this promise to run indefinitely
                // used while debugging
                t = 0;
                rst = function () { return; };
            }

            res = function () {
                clearTimeout(t);
                resolve();
            };

            rej = reject;
        });

        return at = {
            promise: p,
            resolve: res,
            reject: rej,
            reset: rst,
            timeout: t
        };
    }
});

/* framework module members... */

test: function (name, fn, options) {
    var mod = this; // local reference to framework module since promises
                    // run code under the window object

    var defaultOptions = {
        // default max running time is 5 seconds
        timeout: 5000
    }

    options = $$.extend({}, defaultOptions, options);

    // remove timeout when debugging is enabled
    options.timeout = mod.debugging ? -1 : options.timeout;

    // call to QUnit.test()
    test(name, function (assert) {
        // tell QUnit this is an async test so it doesn't run other tests
        // until done() is called
        var done = assert.async();
        return new Promise(function (resolve, reject) {
            console.log("Beginning: " + name);

            var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
            $$(at).one("timeout", function () {
                // assert.fail() is just an extension I made that literally calls
                // assert.ok(false, msg);
                assert.fail("Test timed out");
            });

            // run test function
            var result = fn.call(mod, assert, at.reset);

            // if the test returns a Promise, resolve it before resolving the test promise
            if (result && result.constructor === Promise) {
                // catch unhandled errors thrown by the test so future tests will run
                result.catch(function (error) {
                    var msg = "Unhandled error occurred."
                    if (error) {
                        msg = error.message + "\n" + error.stack;
                    }

                    assert.fail(msg);
                }).then(function () {
                    // resolve the timeout Promise
                    at.resolve();
                    resolve();
                });
            } else {
                // if test does not return a Promise, simply clear the timeout
                // and resolve our test Promise
                at.resolve();
                resolve();
            }
        }).then(function () {
            // tell QUnit that the test is over so that it can clean up and start the next test
            done();
            console.log("Ending: " + name);
        });
    });
}

Bir test zaman aşımına uğrarsa, benim zaman aşımı Promise assert.fail(), testin başarısız olarak işaretlenmesini sağlayacak şekilde teste girecektir, bu tamamen iyi ve iyidir, ancak test Promise ( result) hala çözülmeyi beklediği için test çalışmaya devam eder.

Testimi iptal etmek için iyi bir yola ihtiyacım var. Bunu, çerçeve modülünde this.cancelTestveya başka bir şeyde bir alan oluşturarak then()ve test içinde her seferinde (örneğin her yinelemenin başında ) iptal edip etmemeyi kontrol ederek yapabilirim . Ancak ideal olarak, $$(at).on("timeout", /* something here */)kalan then()e- postaları temizlemek için kullanabilirim .result değişkenimde , böylece testin geri kalanının hiçbiri çalıştırılmaz.

Böyle bir şey var mı?

Hızlı güncelleme

Kullanmayı denedim Promise.race([result, at.promise]). İşe yaramadı.

Güncelleme 2 + kafa karışıklığı

Engelimi kaldırmak için mod.cancelTest, test fikrine / yoklama ile birkaç satır ekledim . (Olay tetikleyicisini de kaldırdım.)

return new Promise(function (resolve, reject) {
    console.log("Beginning: " + name);

    var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
    at.promise.catch(function () {
        // end the test if it times out
        mod.cancelTest = true;
        assert.fail("Test timed out");
        resolve();
    });

    // ...
    
}).then(function () {
    // tell QUnit that the test is over so that it can clean up and start the next test
    done();
    console.log("Ending: " + name);
});

İfadede bir kesme noktası belirledim catchve vuruluyor. Şimdi kafamı karıştıran şey şu kithen() ifadenin çağrılmaması. Fikirler?

Güncelleme 3

Son şeyi çözdüm. fn.call()yakalayamadığım bir hata fırlatıyordu, bu yüzden test sözü, çözemeden önce reddediyordu at.promise.catch().


ES6 vaatleri ile iptal yapmak mümkündür, ancak bu sözün bir özelliği değildir (daha ziyade - onu döndüren işlevin bir özelliğidir) İlgilendiğiniz takdirde kısa bir örnek verebilirim.
Benjamin Gruenbaum

@BenjaminGruenbaum Neredeyse bir yıl olduğunu biliyorum, ancak bir örnek yazmaya vaktiniz varsa yine de ilgileniyorum. :)
dx_over_dt

1
Bir yıl önceydi, ancak dünden iki gün önce iptal jetonları ve 1. aşamaya
geçerken

3
Bir Sözü iptal etmenin ES6 cevabı Gözlemlenebilirdir. Bununla
Frank Goortani

Sözün iptali için kütüphaneyi kullanma konusundaki cevabımı bağlamak Prex.
noseratio

Yanıtlar:


75

.thenJavaScript Promise örneğinin 'lerini temizlemek için bir yöntem var mı ?

Hayır. En azından ECMAScript 6'da değil. Sözler (ve onların thenişleyicileri) varsayılan olarak iptal edilemez (maalesef) . Bunun doğru şekilde nasıl yapılacağına dair es-tartışmada (örneğin burada ) biraz tartışma var , ancak hangi yaklaşım kazanırsa kazansın, ES6'ya girmeyecek.

Mevcut bakış açısı, alt sınıflamanın kendi uygulamanızı kullanarak iptal edilebilir vaatler oluşturmanıza izin vereceğidir (bunun ne kadar işe yarayacağından emin değilsiniz) .

Dil komitesi en iyi yolu bulana kadar (ES7 umarım?) , Çoğu iptal özelliğine sahip kullanıcı bölgesi Promise uygulamalarını kullanmaya devam edebilirsiniz.

Mevcut tartışma https://github.com/domenic/cancelable-promise ve https://github.com/bergus/promise-cancellation taslaklarında yer almaktadır.


2
"Biraz tartışma" - esdiscuss veya GitHub'daki belki 30 konuya bağlantı verebilirim :) (bluebird 3.0'da iptal konusunda kendi yardımınızdan bahsetmiyorum bile)
Benjamin Gruenbaum

@BenjaminGruenbaum: Bu bağlantıların bir yerde paylaşmaya hazır mısınız? Uzun zamandır görüşleri ve girişimleri özetlemek ve tartışmak için bir teklif göndermek istedim, bu yüzden hiçbir şeyi unutmadığımı tekrar kontrol edebilirsem mutlu olurum.
Bergi

Onları işte elimde tutuyorum - bu yüzden 3-4 gün içinde alacağım. İyi bir başlangıç ​​için vaatler-aplus altında vaat iptal spesifikasyonunu kontrol edebilirsiniz.
Benjamin Gruenbaum

1
@ LUH3417: "normal" işlevler bu bakımdan sıkıcı. Bir programı başlatır ve bitene kadar beklersiniz - ya da siz killonu ve yan etkilerin çevrenizde bıraktığı tuhaf durumda görmezden gelirsiniz (bu nedenle, genellikle bunu da atarsınız, örneğin herhangi bir yarı bitmiş çıktı). Engellemeyen veya eşzamansız işlevler, devam eden işlemlerin yürütülmesi üzerinde bu tür daha hassas bir kontrole sahip olmak istediğiniz etkileşimli uygulamalarda çalışmak üzere oluşturulmuştur.
Bergi

6
Domenic , TC39 teklifini kaldırdı ... ... cc @BenjaminGruenbaum
Sergio

50

ES6'da bunu yapmanın standart bir yolu olmasa da, bunu halledecek Bluebird adlı bir kütüphane var .

React belgelerinin bir parçası olarak açıklanan önerilen bir yol da vardır. 2. ve 3. güncellemelerinizdekine benziyor.

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

const cancelablePromise = makeCancelable(
  new Promise(r => component.setState({...}}))
);

cancelablePromise
  .promise
  .then(() => console.log('resolved'))
  .catch((reason) => console.log('isCanceled', reason.isCanceled));

cancelablePromise.cancel(); // Cancel the promise

Alındığı: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html


1
bu iptal tanımı sadece sözü reddetmektir. "iptal edildi" nin tanımına bağlıdır.
Alexander Mills

1
Bir dizi sözü iptal etmek istersen ne olur?
Matthieu Brucher

1
Bu yaklaşımla ilgili sorun, eğer asla çözülmeyecek veya reddetmeyecek bir Sözünüz varsa asla iptal edilmeyecektir.
DaNeSh

2
Bu kısmen doğru, ancak uzun bir söz zinciriniz varsa, bu yaklaşım işe yaramaz.
Veikko Karsikko

11

Kimsenin buna Promise.raceaday olarak bahsetmemesine gerçekten şaşırdım :

const actualPromise = new Promise((resolve, reject) => { setTimeout(resolve, 10000) });
let cancel;
const cancelPromise = new Promise((resolve, reject) => {
    cancel = reject.bind(null, { canceled: true })
})

const cancelablePromise = Object.assign(Promise.race([actualPromise, cancelPromise]), { cancel });

3
Bunun işe yaradığına inanmıyorum. Günlüğe kaydetme sözünü değiştirirseniz, çalıştırma cancel(), günlüğün çağrılmasına neden olur. `` const realPromise = new Promise ((çözümleme, reddetme) => {setTimeout (() => {console.log ('gerçek çağrıldı'); resol ()}, 10000)}); ``
shmck

2
Soru, bir sözün nasıl iptal edileceğiydi (=> thenyürütülecek zincirleme s), iptal etme setTimeout(=> clearTimeout) veya eşzamanlı kodun nasıl iptal edileceği değil , burada her satırdan ( if (canceled) return) sonra if koymazsanız ( ) bu başarılamaz. (Bunu yapma)
Pho3nixHun

10
const makeCancelable = promise => {
    let rejectFn;

    const wrappedPromise = new Promise((resolve, reject) => {
        rejectFn = reject;

        Promise.resolve(promise)
            .then(resolve)
            .catch(reject);
    });

    wrappedPromise.cancel = () => {
        rejectFn({ canceled: true });
    };

    return wrappedPromise;
};

Kullanım:

const cancelablePromise = makeCancelable(myPromise);
// ...
cancelablePromise.cancel();

5

Sözün yerine getirilmesini durdurmak aslında imkansızdır, ancak reddedileni kaçırabilir ve sözün kendisinden çağırabilirsiniz.

class CancelablePromise {
  constructor(executor) {
    let _reject = null;
    const cancelablePromise = new Promise((resolve, reject) => {
      _reject = reject;
      return executor(resolve, reject);
    });
    cancelablePromise.cancel = _reject;

    return cancelablePromise;
  }
}

Kullanım:

const p = new CancelablePromise((resolve, reject) => {
  setTimeout(() => {
    console.log('resolved!');
    resolve();
  }, 2000);
})

p.catch(console.log);

setTimeout(() => {
  p.cancel(new Error('Messed up!'));
}, 1000);

1
@dx_over_dt Düzenlemeniz harika bir yorum olur, ancak düzenleme değildir. Lütfen bu tür kapsamlı düzenlemeleri OP'nin alanına bırakın (gönderi, elbette Topluluk Wiki olarak işaretlenmemişse).
TylerH

@TylerH, yazım hatalarını ve benzerlerini düzeltmek için düzenlemenin amacı nedir? Veya güncel olmayan bilgileri güncellemek için? Başkalarının gönderilerini düzenleme ayrıcalığına yeniyim.
dx_over_dt

@dx_over_dt Evet, düzenleme, yazım hatalarını, dilbilgisi hatalarını düzelterek gönderileri iyileştirmek ve sözdizimi vurgulamaları eklemektir (eğer birisi sadece bir grup kod gönderiyor ancak bunu girintilemiyor veya `` '' ile etiketlemiyorsa). Ek açıklamalar veya şeyler için akıl yürütme / gerekçelendirme gibi önemli içerik eklemek, genellikle yanıtı gönderen kişinin alanıdır. Yorumlarda önermekte özgürsünüz ve OP, yorumdan haberdar edilecek ve daha sonra yanıtlayabilecektir veya önerinizi gönderiye kendileri ekleyebilirler.
TylerH

@dx_over_dt İstisnalar, bir gönderinin ortak bir gönderi olarak hizmet vermesi amaçlandığını belirten "Topluluk Wiki" olarak işaretlenmiş olması (ör. Wikipedia gibi) veya gönderiyle ilgili kaba / küfürlü dil, tehlikeli / zararlı içerik ( örneğin, size virüs vermesi veya tutuklanmanıza neden olabilecek öneriler veya kodlar) veya sağlık kayıtları, telefon numaraları, kredi kartları vb. gibi kişisel bilgiler; bunları kendiniz kaldırmakta özgürsünüz.
TylerH

Bir söz dahilinde yürütmenin durdurulamama nedeninin JavaScript'in tek iş parçacıklı olması olduğunu belirtmek gerekir. Promise işlevi yürütülürken, başka hiçbir şey çalışmadığından, yürütmeyi durdurmayı tetikleyecek hiçbir şey yoktur.
dx_over_dt


2

İşte uygulamamız https://github.com/permettez-moi-de-construire/cancellable-promise

Gibi kullanılmış

const {
  cancellablePromise,
  CancelToken,
  CancelError
} = require('@permettezmoideconstruire/cancellable-promise')

const cancelToken = new CancelToken()

const initialPromise = SOMETHING_ASYNC()
const wrappedPromise = cancellablePromise(initialPromise, cancelToken)


// Somewhere, cancel the promise...
cancelToken.cancel()


//Then catch it
wrappedPromise
.then((res) => {
  //Actual, usual fulfill
})
.catch((err) => {
  if(err instanceOf CancelError) {
    //Handle cancel error
  }

  //Handle actual, usual error
})

hangi :

  • Promise API'ye dokunmuyor
  • catchÇağrı içinde daha fazla iptal yapalım
  • Diğer teklif veya uygulamalardan farklı olarak iptalin çözülmesi yerine reddedilmesine güvenin

Çeker ve yorumlar hoş geldiniz


2

Söz yardımı ile iptal edilebilir AbortController.

Öyleyse temizleme için bir yöntem var mı: evet, sözü AbortControllernesneyle reddedebilir ve sonra promisetüm blokları atlayıp doğrudan catch bloğuna gidebilirsiniz.

Misal:

import "abortcontroller-polyfill";

let controller = new window.AbortController();
let signal = controller.signal;
let elem = document.querySelector("#status")

let example = (signal) => {
    return new Promise((resolve, reject) => {
        let timeout = setTimeout(() => {
            elem.textContent = "Promise resolved";
            resolve("resolved")
        }, 2000);

        signal.addEventListener('abort', () => {
            elem.textContent = "Promise rejected";
            clearInterval(timeout);
            reject("Promise aborted")
        });
    });
}

function cancelPromise() {
    controller.abort()
    console.log(controller);
}

example(signal)
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.log("Catch: ", error)
    });

document.getElementById('abort-btn').addEventListener('click', cancelPromise);

HTML


    <button type="button" id="abort-btn" onclick="abort()">Abort</button>
    <div id="status"> </div>

Not: çoklu dolgu eklemeniz gerekir, tüm tarayıcılarda desteklenmez.

Canlı Örnek

Zarif-göl-5jnh3 düzenleyin


1

basit versiyon :

sadece reddetme işlevini verin.

function Sleep(ms,cancel_holder) {

 return new Promise(function(resolve,reject){
  var done=false; 
  var t=setTimeout(function(){if(done)return;done=true;resolve();}, ms);
  cancel_holder.cancel=function(){if(done)return;done=true;if(t)clearTimeout(t);reject();} 
 })
}

bir sargı çözümü (fabrika)

bulduğum çözüm bir cancel_holder nesnesi geçirmektir. iptal işlevi olacaktır. bir iptal işlevi varsa, iptal edilebilir.

Bu iptal işlevi, sözü Hata ('iptal edildi') ile reddeder.

Çözümlemeden, reddetmeden veya on_cancel'den önce iptal işlevinin sebepsiz olarak çağrılmasını önler.

İptal işlemini enjeksiyonla geçmeyi uygun buldum

function cancelablePromise(cancel_holder,promise_fn,optional_external_cancel) {
  if(!cancel_holder)cancel_holder={};
  return new Promise( function(resolve,reject) {
    var canceled=false;
    var resolve2=function(){ if(canceled) return; canceled=true; delete cancel_holder.cancel; resolve.apply(this,arguments);}
    var reject2=function(){ if(canceled) return; canceled=true; delete cancel_holder.cancel; reject.apply(this,arguments);}
    var on_cancel={}
    cancel_holder.cancel=function(){
      if(canceled) return; canceled=true;

      delete cancel_holder.cancel;
      cancel_holder.canceled=true;

      if(on_cancel.cancel)on_cancel.cancel();
      if(optional_external_cancel)optional_external_cancel();

      reject(new Error('canceled'));
    };

    return promise_fn.call(this,resolve2,reject2,on_cancel);        
  });
}

function Sleep(ms,cancel_holder) {

 return cancelablePromise(cancel_holder,function(resolve,reject,oncacnel){

  var t=setTimeout(resolve, ms);
  oncacnel.cancel=function(){if(t)clearTimeout(t);}     

 })
}


let cancel_holder={};

// meanwhile in another place it can be canceled
setTimeout(function(){  if(cancel_holder.cancel)cancel_holder.cancel(); },500) 

Sleep(1000,cancel_holder).then(function() {
 console.log('sleept well');
}, function(e) {
 if(e.message!=='canceled') throw e;
 console.log('sleep interrupted')
})

1

Promise-abortable'ı deneyin : https://www.npmjs.com/package/promise-abortable

$ npm install promise-abortable
import AbortablePromise from "promise-abortable";

const timeout = new AbortablePromise((resolve, reject, signal) => {
  setTimeout(reject, timeToLive, error);
  signal.onabort = resolve;
});

Promise.resolve(fn()).then(() => {
  timeout.abort();
});

1

Kodunuz bir sınıfa yerleştirilmişse, bunun için bir dekoratör kullanabilirsiniz. Utils-decorators ( npm install --save utils-decorators) içinde böyle bir dekoratörünüz var . Önceki çağrının çözümlenmesinden önce o belirli yöntem için başka bir çağrı yapılmışsa, dekore edilmiş yöntemin önceki çağrısını iptal edecektir.

import {cancelPrevious} from 'utils-decorators';

class SomeService {

   @cancelPrevious()
   doSomeAsync(): Promise<any> {
    ....
   }
}

https://github.com/vlio20/utils-decorators#cancelprevious-method


0

Tüm bunların / yakalamaların yürütülmesini durdurmak istiyorsanız, asla çözülmeyecek bir söz enjekte ederek bunu yapabilirsiniz. Muhtemelen bellek sızıntısı provizyonları vardır, ancak sorunu çözecektir ve çoğu uygulamada çok fazla boşa harcanmasına neden olmamalıdır.

new Promise((resolve, reject) => {
    console.log('first chain link executed')
    resolve('daniel');
}).then(name => {
    console.log('second chain link executed')
    if (name === 'daniel') {
        // I don't want to continue the chain, return a new promise
        // that never calls its resolve function
        return new Promise((resolve, reject) => {
            console.log('unresolved promise executed')
        });
    }
}).then(() => console.log('last chain link executed'))

// VM492:2 first chain link executed
// VM492:5 second chain link executed
// VM492:8 unresolved promise executed

0

Promise'de sinyal vermek then()ve catch()erken çıkmak için "iptal edilmiş" bir özellik ayarlayın . Özellikle mevcut mikro görevlerin onmessageişleyicilerden Promises'te sıraya girdiği Web Çalışanları için çok etkilidir .

// Queue task to resolve Promise after the end of this script
const promise = new Promise(resolve => setTimeout(resolve))

promise.then(_ => {
  if (promise.canceled) {
    log('Promise cancelled.  Exiting early...');
    return;
  }

  log('No cancelation signaled.  Continue...');
})

promise.canceled = true;

function log(msg) {
  document.body.innerHTML = msg;
}


0

@Michael Yagudaev'in cevabı benim için çalışıyor.

Ancak orijinal yanıt, reddetme işleminin üstesinden gelmek için sarılmış sözü .catch () ile zincirlemedi, işte @Michael Yagudaev'in cevabına ek olarak iyileştirmem:

const makeCancelablePromise = promise => {
  let hasCanceled = false;
  const wrappedPromise = new Promise((resolve, reject) => {
    promise
      .then(val => (hasCanceled ? reject({ isCanceled: true }) : resolve(val)))
      .catch(
        error => (hasCanceled ? reject({ isCanceled: true }) : reject(error))
      );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled = true;
    }
  };
};

// Example Usage:
const cancelablePromise = makeCancelable(
  new Promise((rs, rj) => {
    /*do something*/
  })
);
cancelablePromise.promise.then(() => console.log('resolved')).catch(err => {
  if (err.isCanceled) {
    console.log('Wrapped promise canceled');
    return;
  }
  console.log('Promise was not canceled but rejected due to errors: ', err);
});
cancelablePromise.cancel();

0

Eğer p bir Söz içeren bir değişkense, o p.then(empty);zaman sonunda tamamlandığında veya zaten tamamlandığında sözden vazgeçmelidir (evet, bunun orijinal soru olmadığını biliyorum, ama sorum bu). "boş" dır function empty() {}. Ben sadece yeni başlayan biriyim ve muhtemelen yanılıyorum, ancak bu diğer cevaplar çok karmaşık görünüyor. Sözler basit olmalı.


0

Hala bu fikir üzerinde çalışıyorum, ancak burada iptal edilebilir bir Sözü kullanarak nasıl gerçekleştirdim setTimeout örnek olarak edilebilir bir .

Buradaki fikir, bir sözün, ne zaman olduğuna karar verdiğinizde çözülmesi veya reddedilmesidir; bu nedenle, ne zaman iptal etmek istediğinize karar vermek, kriteri karşılamak ve ardından reject()işlevi kendiniz çağırmak olmalıdır .

  • Birincisi, bir sözü erken bitirmek için iki neden olduğunu düşünüyorum: onu bitirmek ve yerine getirmek (buna çözüm olarak adlandırdım ) ve iptal etmek (buna reddetmek diyorum ). Tabii ki, bu sadece benim hissim. Elbette bir Promise.resolve()yöntem var, ancak bu kurucunun kendisinde ve kukla bir çözülmüş söz veriyor. Bu örnek resolve()yöntem aslında somutlaştırılmış bir vaat nesnesini çözer.

  • Önce geri İkincisi, mutlu bir yeni oluşturulan söz nesnesine böyle bir şey ekleyebilir ve sadece eklemiş böylece resolve()ve reject()yöntemler kendi kendine yeten bunu yapmak için.

  • Üçüncüsü, işin püf noktası, uygulayıcıya resolveve rejectişlevlere daha sonra erişebilmektir , bu yüzden onları kapağın içinden basit bir nesnede sakladım.

Çözümün basit olduğunu düşünüyorum ve bununla ilgili herhangi bir büyük sorun göremiyorum.

function wait(delay) {
  var promise;
  var timeOut;
  var executor={};
  promise=new Promise(function(resolve,reject) {
    console.log(`Started`);
    executor={resolve,reject};  //  Store the resolve and reject methods
    timeOut=setTimeout(function(){
      console.log(`Timed Out`);
      resolve();
    },delay);
  });
  //  Implement your own resolve methods,
  //  then access the stored methods
      promise.reject=function() {
        console.log(`Cancelled`);
        clearTimeout(timeOut);
        executor.reject();
      };
      promise.resolve=function() {
        console.log(`Finished`);
        clearTimeout(timeOut);
        executor.resolve();
      };
  return promise;
}

var promise;
document.querySelector('button#start').onclick=()=>{
  promise=wait(5000);
  promise
  .then(()=>console.log('I have finished'))
  .catch(()=>console.log('or not'));
};
document.querySelector('button#cancel').onclick=()=>{ promise.reject(); }
document.querySelector('button#finish').onclick=()=>{ promise.resolve(); }
<button id="start">Start</button>
<button id="cancel">Cancel</button>
<button id="finish">Finish</button>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.