바닐라 ECMAScript 6 Promise 체인 취소


110

.thenJavaScript Promise인스턴스 를 지우는 방법이 있습니까?

QUnit 위에 JavaScript 테스트 프레임 워크를 작성했습니다 . 프레임 워크는 .NET Framework에서 각각을 실행하여 테스트를 동 기적으로 실행합니다 Promise. (이 코드 블록의 길이에 대해 죄송합니다. 가능한 한 댓글을 달았으므로 지루하지 않게 느껴졌습니다.)

/* 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);
        });
    });
}

테스트가 시간 초과되면 내 시간 초과 Promise가 assert.fail()테스트에서 테스트를 수행하여 테스트가 실패로 표시됩니다. 이는 모두 훌륭하고 양호하지만 테스트 Promise ( result)가 여전히 문제를 해결하기를 기다리고 있기 때문에 테스트가 계속 실행 됩니다.

시험을 취소 할 좋은 방법이 필요합니다. 프레임 워크 모듈 this.cancelTest이나 무언가 에 필드를 만들고 then()테스트 내에서 매번 (예 : 각 반복 시작시 ) 취소할지 여부를 확인하여 수행 할 수 있습니다. 그러나 이상적으로 는 나머지 테스트가 실행되지 않도록 내 변수 $$(at).on("timeout", /* something here */)의 나머지 then()s 를 지우는 데 사용할 수 있습니다 result.

이와 같은 것이 존재합니까?

빠른 업데이트

나는 Promise.race([result, at.promise]). 작동하지 않았습니다.

업데이트 2 + 혼란

나를 차단 해제하기 mod.cancelTest위해 테스트 아이디어 내에 / polling 으로 몇 줄을 추가했습니다 . (이벤트 트리거도 제거했습니다.)

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);
});

나는 catch성명서에 중단 점을 설정 했고 그것이 맞았다. 지금 나를 혼란스럽게하는 것은 그 then()진술이 호출되지 않는다는 것입니다. 아이디어?

업데이트 3

마지막 일을 알아 냈습니다. fn.call()내가 잡지 못한 오류를 던지고 있었기 때문에 테스트 약속은 전에 거부 at.promise.catch()되었습니다.


ES6 프라 미스로 취소를 할 수는 있지만 프라 미스의 속성이 아닙니다 (보단-그것을 반환하는 함수의 속성입니다) 관심이 있다면 짧은 예제를 만들 수 있습니다.
Benjamin Gruenbaum 2015

@BenjaminGruenbaum 거의 1 년이 지났다는 것을 알고 있지만 예제를 작성할 시간이 있다면 여전히 관심이 있습니다. :)
dx_over_dt

1
1 년 전 이었지만 어제 이틀 전에 취소 토큰과 취소 가능한 약속이 1 단계로 이동하면서 공식적으로 논의되었습니다.
Benjamin Gruenbaum 2016 년

3
약속 취소에 대한 ES6 답변은 관찰 가능합니다. 여기에서이에 대한 자세한 내용을보실 수 있습니다 : github.com/Reactive-Extensions/RxJS
프랭크 Goortani

약속 취소 를 위해 라이브러리 사용에 대한 내 대답 을 연결 Prex합니다.
noseratio

답변:


75

.thenJavaScript Promise 인스턴스 를 지우는 방법이 있습니까?

아니요. 적어도 ECMAScript 6에는 없습니다. 약속 (및 해당 then처리기)은 기본적으로 취소 할 수 없습니다 (불행히도) . 이 작업을 올바른 방식으로 수행하는 방법에 대한 es-discuss (예 : 여기 )에 대한 약간의 논의가 있지만 어떤 접근 방식이 이길 지 ES6에는 적용되지 않습니다.

현재 관점은 서브 클래 싱이 자신의 구현을 사용하여 취소 할 수있는 약속을 만들 수 있다는 것입니다 (얼마나 잘 작동하는지 확실하지 않음) .

언어 커밋이 가장 좋은 방법을 찾을 때까지 (ES7 바라건대?) 여전히 userland Promise 구현을 사용할 수 있으며, 그중 많은 기능이 취소됩니다.

현재 토론은 https://github.com/domenic/cancelable-promisehttps://github.com/bergus/promise-cancellation 초안에 있습니다.


2
"A는 토론의 비트"- 나는 esdiscuss 또는 GitHub의에 어쩌면 30 스레드에 링크 할 수 있습니다 : (블루 버드 3.0의 취소와 함께 자신의 도움을 언급하지 않기 위하여)
벤자민 Gruenbaum

@BenjaminGruenbaum : 링크를 공유 할 준비가 되었나요? 나는 오랫동안 의견과 시도를 요약하고 토론 제안서를 게시하고 싶었 기 때문에 아무것도 잊은 것이 없다는 것을 다시 확인할 수 있으면 기쁠 것입니다.
Bergi

직장에서 편리하게 사용할 수 있으므로 3 ~ 4 일 내에 보관합니다. 좋은 시작을 위해 promises-aplus에서 promise 취소 사양을 확인할 수 있습니다.
Benjamin Gruenbaum 2015

1
@ LUH3417 : "정상"기능은 그런 점에서 지루합니다. 프로그램을 시작하고 완료 될 때까지 기다립니다. 또는 kill부작용이 환경을 떠난 이상한 상태에서 무시합니다 (따라서 일반적으로 반 완성 된 결과물도 버립니다). 그러나 비 차단 또는 비동기 함수는 진행중인 작업의 실행을보다 세밀하게 제어하려는 대화 형 애플리케이션에서 작동하도록 구축되었습니다.
Bergi

6
Domenic는 TC39 제안 ... 제거 ... CC의 @BenjaminGruenbaum
세르지오

50

ES6에서이를 수행하는 표준 방법은 없지만이 를 처리하기위한 Bluebird 라는 라이브러리 가 있습니다.

반응 문서의 일부로 설명 된 권장 방법도 있습니다. 2 차 및 3 차 업데이트에있는 것과 비슷해 보입니다.

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

출처 : https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html


1
취소됨에 대한이 정의는 약속을 거부하는 것입니다. "취소됨"의 정의에 따라 다릅니다.
Alexander Mills

1
약속을 취소하려면 어떻게됩니까?
Matthieu Brucher

1
이 접근 방식의 문제점은 해결하거나 거부하지 않는 Promise가 있으면 취소되지 않는다는 것입니다.
DaNeSh

2
이것은 부분적으로 옳지 만 약속 체인이 길면이 접근 방식이 작동하지 않습니다.
Veikko Karsikko

11

아무도 Promise.race이것에 대한 후보로 언급하지 않는다는 것에 정말 놀랐습니다 .

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
나는 이것이 효과가 있다고 믿지 않는다. 로그 약속을 변경해도 실행 cancel()하면 로그 가 계속 호출됩니다. ```const actualPromise = new Promise ((resolve, reject) => {setTimeout (() => {console.log ( 'actual called'); resolve ()}, 10000)}); ```
shmck

2
문제는 then취소 setTimeout(=> clearTimeout) 또는 동기 코드가 아니라 프라 미스 (=> 실행될 체인 중지)를 취소하는 방법이었습니다. 각 줄 ( if (canceled) return) 뒤에 if를 입력하지 않으면 달성 할 수 없습니다. (하지 마십시오)
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;
};

용법:

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

5

실제로 약속 실행을 중지하는 것은 불가능하지만 거부를 가로 채서 약속 자체에서 호출 할 수 있습니다.

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

    return cancelablePromise;
  }
}

용법:

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 귀하의 편집은 훌륭한 코멘트이지만 편집은 아닙니다. 이러한 실질적인 수정 사항은 OP의 범위에 남겨주세요 (물론 게시물이 Community Wiki로 표시되지 않는 한).
TylerH

@TylerH 그래서 오타 등을 수정하는 편집의 요점입니까? 아니면 오래된 정보를 업데이트하려면? 다른 사람의 게시물 권한을 편집하는 기능이 처음입니다.
dx_over_dt

@dx_over_dt 예, 편집은 오타, 문법 오류를 수정하고 구문 강조를 추가하여 게시물을 개선하는 것입니다 (예를 들어 누군가가 코드를 많이 게시하지만 들여 쓰기 또는 태그를 붙이지 않는 경우). 추가 설명이나 사물에 대한 추론 / 사유와 같은 실질적인 콘텐츠를 추가하는 것은 일반적으로 답변을 게시 한 사람의 범위입니다. 댓글로 자유롭게 제안 할 수 있으며, OP는 댓글에 대한 알림을 받고 응답 할 수 있습니다. 또는 제안 사항을 게시물 자체에 통합 할 수도 있습니다.
TylerH

@dx_over_dt 게시물이 "커뮤니티 위키"로 표시된 경우 (예 : Wikipedia와 같은) 공동 게시물로 사용하거나 무례한 / 학대적인 언어, 위험 / 유해한 콘텐츠와 같은 게시물에 심각한 문제가있는 경우는 예외입니다. 예 : 바이러스를 제공하거나 체포 될 수있는 제안 또는 코드) 또는 건강 기록, 전화 번호, 신용 카드 등과 같은 개인 정보; 직접 제거하십시오.
TylerH

약속 내에서 실행을 중단 할 수없는 이유는 JavaScript가 단일 스레드이기 때문이라는 점에 주목할 가치가 있습니다. promise 함수가 실행되는 동안 다른 것은 실행되지 않으므로 실행 중지를 트리거 할 수 없습니다.
dx_over_dt


2

다음은 우리의 구현입니다 https://github.com/permettez-moi-de-construire/cancellable-promise

같이 사용

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
})

어느 :

  • Promise API를 건드리지 않음
  • catch전화 내에서 추가로 취소하겠습니다.
  • 다른 제안이나 구현과 달리 해결 되지 않고 거부 되는 취소에 의존

가져 오기 및 의견 환영


2

의 도움으로 약속을 취소 할 수 있습니다 AbortController.

그 다음을 지우는 방법이 있습니까 : 예, AbortController객체와 의 약속을 거부하면 promise모든 then 블록을 우회하고 catch 블록으로 직접 이동할 수 있습니다.

예:

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>

참고 : 모든 브라우저에서 지원되는 것은 아니지만 polyfill을 추가해야합니다.

라이브 예

elegant-lake-5jnh3 편집


1

간단한 버전 :

거부 기능을 제공하십시오.

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();} 
 })
}

포장기 솔루션 (공장)

내가 찾은 해결책은 cancel_holder 객체를 전달하는 것입니다. 취소 기능이 있습니다. 취소 기능이 있으면 취소 할 수 있습니다.

이 취소 함수는 Error ( 'canceled')와 함께 약속을 거부합니다.

resolve, reject 또는 on_cancel 전에는 취소 함수가 이유없이 호출되는 것을 방지합니다.

취소 작업을 주입으로 전달하는 것이 편리하다는 것을 알았습니다.

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 시도 : 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

코드가 클래스에 배치되면 데코레이터를 사용할 수 있습니다. utils-decorators ( npm install --save utils-decorators) 에 이러한 데코레이터가 있습니다. 이전 호출을 해결하기 전에 해당 특정 메서드에 대한 다른 호출이 발생한 경우 데코 레이팅 된 메서드의 이전 호출을 취소합니다.

import {cancelPrevious} from 'utils-decorators';

class SomeService {

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

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


0

모든 thens / catch가 실행되는 것을 중지하려면 해결되지 않는 promise를 삽입하여이를 수행 할 수 있습니다. 아마도 메모리 누수 반복이있을 수 있지만 문제를 해결하고 대부분의 응용 프로그램에서 너무 많은 메모리를 낭비하지 않아야합니다.

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

신호를 약속에 "취소"속성을 설정 then()catch()조기 종료 할 수 있습니다. 특히 onmessage핸들러의 Promises에 기존 마이크로 태스크가 대기열에있는 Web Workers에서 매우 효과적 입니다.

// 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의 답변이 저에게 효과적입니다.

그러나 원래 답변은 거부 처리를 처리하기 위해 래핑 된 약속을 .catch ()로 연결하지 않았습니다. 여기 @Michael Yagudaev의 답변 위에 개선 사항이 있습니다.

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

p가 Promise를 포함하는 변수 인 p.then(empty);경우, 결국 완료되거나 이미 완료된 경우 promise를 무시해야합니다 (예, 이것이 원래 질문이 아니라는 것을 알고 있지만 제 질문입니다). "비어 있음"은 function empty() {}입니다. 나는 단지 초보자이고 아마도 틀렸을 것입니다. 그러나 다른 대답은 너무 복잡해 보입니다. 약속은 단순해야합니다.


0

나는 여전히이 아이디어를 통해 작업하고 있지만 여기 setTimeout에 예제로 사용하여 취소 가능한 약속을 구현 한 방법이 있습니다 .

Promise는 약속이 결정될 때마다 해결되거나 거부되므로 취소 할시기를 결정하고 기준을 충족 한 다음 reject()직접 함수 를 호출해야 합니다.

  • 첫째, 약속을 일찍 끝내는 데는 두 가지 이유가 있다고 생각합니다. 약속을 끝내고 끝내는 것 ( Resolve 이라고 부름 )과 취소 ( Reject 라고 부른 것 )입니다. 물론 그것은 내 느낌입니다. 물론 Promise.resolve()메서드가 있지만 생성자 자체에 있으며 더미 해결 된 약속을 반환합니다. 이 인스턴스 resolve()메서드는 실제로 인스턴스화 된 promise 개체를 해결합니다.

  • 둘째, 새로 생성 된 promise 객체를 반환하기 전에 원하는 것을 기꺼이 추가 할 수 있습니다. 그래서 방금 추가 resolve()하고 reject()자체 포함되도록 메서드를 추가 했습니다.

  • 셋째, 트릭은 나중에 executor resolvereject함수 에 액세스 할 수있는 것이므로 클로저 내에서 간단한 객체에 저장했습니다.

해결책은 간단하다고 생각하며 큰 문제는 보이지 않습니다.

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>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.