{"id":15030090,"url":"https://github.com/jdeferred/jdeferred","last_synced_at":"2025-05-15T07:06:04.649Z","repository":{"id":7258587,"uuid":"8570603","full_name":"jdeferred/jdeferred","owner":"jdeferred","description":"Java Deferred/Promise library similar to JQuery.","archived":false,"fork":false,"pushed_at":"2021-01-18T14:17:36.000Z","size":804,"stargazers_count":1504,"open_issues_count":33,"forks_count":179,"subscribers_count":62,"default_branch":"master","last_synced_at":"2025-04-14T12:58:43.051Z","etag":null,"topics":["android","async","java","promise","promise-library"],"latest_commit_sha":null,"homepage":"jdeferred.org","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdeferred.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-03-05T02:43:57.000Z","updated_at":"2025-04-07T14:10:33.000Z","dependencies_parsed_at":"2022-08-25T23:22:04.257Z","dependency_job_id":null,"html_url":"https://github.com/jdeferred/jdeferred","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdeferred%2Fjdeferred","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdeferred%2Fjdeferred/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdeferred%2Fjdeferred/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdeferred%2Fjdeferred/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdeferred","download_url":"https://codeload.github.com/jdeferred/jdeferred/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292042,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","async","java","promise","promise-library"],"created_at":"2024-09-24T20:12:25.100Z","updated_at":"2025-05-15T07:05:59.613Z","avatar_url":"https://github.com/jdeferred.png","language":"Java","readme":"\u003c!--\n  Copyright 2013-2018 Ray Tsang\n  \n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n  \n    http://www.apache.org/licenses/LICENSE-2.0\n  \n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n--\u003e\n\nJDeferred 2.x\n==============\n\nJDeferred is a Java Deferred/Promise library similar to JQuery's Deferred Object.\n\nInspired by [JQuery](https://github.com/jquery/jquery) and [Android Deferred Object](https://github.com/CodeAndMagic/android-deferred-object).\n\nIf you are using JDeferred 1.x, see [JDeferred 1.x Documentation](http://jdeferred.org/v1/)\n\n\u003ca name=\"features\"\u003e\u003c/a\u003eFeatures\n--------\n* Deferred object and Promise\n* Promise callbacks\n  * ```.then(…)```\n  * ```.filter(…)```\n  * ```.pipe(…)```\n  * ```.done(…)```\n  * ```.fail(…)```\n  * ```.progress(…)```\n  * ```.always(…)```\n  * ```.pipeAlways(…)```\n* Multiple promises\n  * ```.when(p1, p2, p3, …).then(…)```\n  * ```.race(p1, p2, p3, …).then(…)```\n  * ```.settle(p1, p2, p3, …).then(…)```\n* Callable and Runnable wrappers\n  * ```.when(new Runnable() {…})```\n  * ```.race(new Runnable() {…})```\n  * ```.settle(new Runnable() {…})```\n* Uses Executor Service\n* Java Generics support\n  * ```Deferred\u003cInteger, Exception, Double\u003e deferred;```\n  * ```deferred.resolve(10);```\n  * ```deferred.reject(new Exception());```\n  * ```deferred.notify(0.80);```\n* Android Support\n* Java 8 Lambda friendly\n* Yes it's on Maven Central Repository!\n\nMaven\n-----\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.jdeferred.v2\u003c/groupId\u003e\n    \u003cartifactId\u003ejdeferred-core\u003c/artifactId\u003e\n    \u003cversion\u003e${version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle\n-----\n```\ncompile 'org.jdeferred.v2:jdeferred-core:${version}'\n```\n\nFind available versions on [Maven Central Repository](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.jdeferred.v2%22%20AND%20a%3A%22jdeferred-core%22).\n\n\u003ca name=\"compatibility\"\u003e\u003c/a\u003eCompatibility\n==============\nCompatibility reports between versions:\n- [1.2.6 to 2.0.0](http://jdeferred.org/compatibility-report-2.0.0.html)\n\n\u003ca name=\"examples\"\u003e\u003c/a\u003eQuick Examples\n==============\n\n\u003ca name=\"examples-deferred-promise\"\u003e\u003c/a\u003eDeferred object and Promise\n---------------------------\n\n```java\nDeferred deferred = new DeferredObject();\nPromise promise = deferred.promise();\npromise.done(new DoneCallback() {\n  public void onDone(Object result) {\n    ...\n  }\n}).fail(new FailCallback() {\n  public void onFail(Object rejection) {\n    ...\n  }\n}).progress(new ProgressCallback() {\n  public void onProgress(Object progress) {\n    ...\n  }\n}).always(new AlwaysCallback() {\n  public void onAlways(State state, Object result, Object rejection) {\n    ...\n  }\n});\n```\nWith the reference to deferred object, you can then trigger actions/updates:\n\n```java\ndeferred.resolve(\"done\");\ndeferred.reject(\"oops\");\ndeferred.notify(\"100%\");\n```\n\n\u003ca name=\"example-filter\"\u003e\u003c/a\u003eFilter\n-----------\n\u003e Use `.filter(...)` instead of `.then(...)` since 2.0.0-Beta2\n\n```java\nDeferred d = …;\nPromise p = d.promise();\nPromise filtered = p.filter(new DoneFilter\u003cInteger, Integer\u003e() {\n  public Integer filterDone(Integer result)\n    return result * 10;\n  }\n});\n\nfiltered.done(new DoneCallback\u003cInteger\u003e() {\n  public void onDone(Integer result) {\n    // result would be original * 10\n    System.out.println(result);\n  }\n});\n\nd.resolve(3) -\u003e 30.\n```\n\n\u003ca name=\"example-pipe\"\u003e\u003c/a\u003ePipe\n----\n\u003e Use `.pipe(...)` instead of `.then(...)` since 2.0.0-Beta2\n\n```java\nDeferred d = ...;\nPromise p = d.promise();\n\np.pipe(new DonePipe\u003cInteger, Integer, Exception, Void\u003e() {\n  public Deferred\u003cInteger, Exception, Void\u003e pipeDone(Integer result) {\n    if (result \u003c 100) {\n      return new DeferredObject\u003cInteger, Void, Void\u003e().resolve(result);\n    } else {\n      return new DeferredObject\u003cInteger, Void, Void\u003e().reject(new Exception(...));\n    }\n  }\n}).done(...).fail(...);\n\nd.resolve(80) -\u003e done!\nd.resolve(100) -\u003e fail!\n\n```\n\n\u003ca name=\"example-dm\"\u003e\u003c/a\u003eDeferred Manager\n----------------\n```java\nDeferredManager dm = new DefaultDeferredManager();\nPromise p1, p2, p3;\n// initialize p1, p2, p3\ndm.when(p1, p2, p3)\n  .done(…)\n  .fail(…)\n```\nYou can also specify a Executor Service for your need.\n\n```\nDeferredManager dm = new DefaultDeferredManager(myExecutorService);\n```\n\n\u003ca name=\"example-runnable-callable\"\u003e\u003c/a\u003eRunnable and Callable\n---------------------\nYou can use Callable and Runnable almost like a Promise without any additional work.\n\n```java\nDeferredManager dm = new DefaultDeferredManager();\ndm.when(new Callable\u003cInteger\u003e(){\n  public Integer call() {\n    // return something\n    // or throw a new exception\n  }\n}).done(new DoneCallback\u003cInteger\u003e() {\n  public void onDone(Integer result) {\n    ...\n  }\n}).fail(new FailCallback\u003cThrowable\u003e() {\n  public void onFail(Throwable e) {\n    ...\n  }\n});\n```\n\nIf you need to notify progress within your Callable or Runnable, you either need to create your own Deferred object and Promise, or you can use DeferredCallable and DeferredRunnable.\n\nUse your own Deferred object\n\n```java\nfinal Deferred deferred = ...\nPromise promise = deferred.promise();\npromise.then(…);\nRunnable r = new Runnable() {\n  public void run() {\n    while (…) {\n      deferred.notify(myProgress);\n    }\n    deferred.resolve(\"done\");\n  }\n}\n```\n\nOr, extending DeferredRunnable\n\n```java\nDeferredManager dm = …;\ndm.when(new DeferredRunnable\u003cDouble\u003e(){\n  public void run() {\n    while (…) {\n      notify(myProgress);\n    }\n  }\n}).then(…);\n```\n\n\u003ca name=\"example-wait\"\u003e\u003c/a\u003eWait and WaitSafely\n-------------------\n\u003e Since 1.0.1\n\nNormally, when using this framework, you would want to do things asynchronously.  However, if there is a need to wait for all deferred tasks to finish, you can use Object.wait or Promise.waitSafely methods.\n\n```java\nPromise p = dm.when(...)\n  .done(...)\n  .fail(...)\n\nsynchronized (p)\n  while (p.isPending()) {\n    try {\n      p.wait();\n    } catch (InterruptedException e) { ... }\n  }\n}\n```\n\nAlternatively, you can use a more simplified shortcut\n```java\nPromise p = dm.when(...)\n  .done(...)\n  .fail(...)\n\ntry {\n  p.waitSafely();\n} catch (InterruptedException e) {\n  ... \n}\n```\n\n\u003ca name=\"example-lambda\"\u003e\u003c/a\u003eJava 8 Lambda\n-------------\nNow this is pretty cool when used with Java 8 Lambda!\n\n```Java\ndm.when(() -\u003e {\n  return \"Hey!\";\n}).done(r -\u003e System.out.println(r));\n\ndm.when(\n  () -\u003e { return \"Hello\"; },\n  () -\u003e { return \"World\"; }\n).done(rs -\u003e\n  rs.forEach(r -\u003e System.out.println(r.getResult()))\n);\n```\n\n\u003ca name=\"example-race\"\u003e\u003c/a\u003eWhen\n-------------\nCalls to `when` with multiple arguments results in a `Promise` that signals `fail` on the first rejection or signals\n`done` with all computed values.\n\n#### Success scenario\n```Java\nCallable\u003cInteger\u003e c1 = () -\u003e 1;\nCallable\u003cInteger\u003e c2 = () -\u003e 2;\nCallable\u003cInteger\u003e c3 = () -\u003e 3;\nPromise\u003cMultipleResults3\u003cInteger, Integer, Integer\u003e, OneReject\u003cThrowable\u003e, MasterProgress\u003e p = dm.when(c1, c2, c3);\np.done(MultipleResults3\u003cInteger, Integer, Integer\u003e r -\u003e {\n  Assert.assertEquals(r.getFirst(), 1);\n  Assert.assertEquals(r.getSecond(), 2);\n  Assert.assertEquals(r.getThird(), 3);\n});\n```\n\n#### Failure scenario\n```Java\nCallable\u003cInteger\u003e c1 = () -\u003e 1;\nCallable\u003cInteger\u003e c2 = () -\u003e 2;\nCallable\u003cInteger\u003e c3 = () -\u003e throw new RuntimeException(\"boom!\");\nPromise\u003cMultipleResults3\u003cInteger, Integer, Integer\u003e, OneReject\u003cThrowable\u003e, MasterProgress\u003e p = dm.when(c1, c2, c3);\np.done(MultipleResults3\u003cInteger, Integer, Integer\u003e r -\u003e Assert.fail(\"should not be called\"))\n .fail(OneReject\u003cThrowable\u003e r -\u003e Assert.assertEquals(r.getReject().getMessage(), \"boom!\"));\n```\n\u003e Since 2.0.0\n\nCalls to `when` with multiple arguments (up to five) will produce results with typesafe getters.\n\n\u003ca name=\"example-when\"\u003e\u003c/a\u003eRace\n-------------\n\u003e Since 2.0.0\n\nCalls to `race` with multiple arguments results in a `Promise` that signals `fail` on the first rejection or signals\n`done` on the first resolution.\n\n#### Success scenario\n```Java\nCallable\u003cInteger\u003e c1 = () -\u003e { Thread.sleep(200); return 1; };\nCallable\u003cInteger\u003e c2 = () -\u003e { Thread.sleep(100); return 2; };\nCallable\u003cInteger\u003e c3 = () -\u003e { Thread.sleep(200); return 3; };\nPromise\u003cOneResult\u003c?\u003e, OneReject\u003cThrowable\u003e, Void\u003e p = dm.race(c1, c2, c3);\np.done(OneResult\u003c?\u003e r -\u003e Assert.assertEquals(r.getResult(), 2));\n```\n#### Failure scenario\n```Java\nCallable\u003cInteger\u003e c1 = () -\u003e { Thread.sleep(200); return 1; };\nCallable\u003cInteger\u003e c2 = () -\u003e { Thread.sleep(100); throw new RuntimeException(\"boom!\"); };\nCallable\u003cInteger\u003e c3 = () -\u003e { Thread.sleep(200); return 3; };\nPromise\u003cOneResult\u003c?\u003e, OneReject\u003cThrowable\u003e, Void\u003e p = dm.race(c1, c2, c3);\np.done(OneResult\u003c?\u003e r -\u003e Assert.fail(\"should not be called\")\n  .fail(OneReject\u003cThrowable\u003e r -\u003e Assert.assertEquals(r.getReject().getMessage(), \"boom!\"));\n```\n\n\u003ca name=\"example-settle\"\u003e\u003c/a\u003eSettle\n-------------\n\u003e Since 2.0.0\n\nCalls to `settle` with multiple arguments results in a `Promise` that collects all resolutions and rejections.\n\n```Java\nCallable\u003cInteger\u003e c1 = () -\u003e { Thread.sleep(200); return 1; };\nCallable\u003cInteger\u003e c2 = () -\u003e { Thread.sleep(100); throw new RuntimeException(\"boom!\"); };\nCallable\u003cInteger\u003e c3 = () -\u003e { Thread.sleep(200); return 3; };\nPromise\u003cAllValues, Throwable, MasterProgress\u003e, Void\u003e p = dm.race(c1, c2, c3);\np.done(AllValues r -\u003e {\n  Assert.assertEquals(r.get(0).getValue(), 1);\n  Assert.assertTrue(r.get(1).getValue() instanceof RuntimeException);\n  Assert.assertEquals(r.get(2).getValue(), 3);\n});\n```\n\n\u003ca name=\"example-cancellation\"\u003e\u003c/a\u003eCancellation Handler\n-------------\n\u003e Since 2.0.0\n\nSometimes a task may be cancelled while its running and would require ti cleanup any resources it may have allocated. You\nmay define a task that implements the `org.jdeferred2.CancellationHandler` interface or pass and extra argument to\n`DeferredFutureTask` with such implementation, for example\n\n```Java\nfinal DataSource datasource = ...;\nclass DatabaseTask extends Runnable, CancellationHandler {\n  @Override\n  public void run() {\n    // perform computation with datasource\n  }\n\n  @Override\n  public void onCancel() {\n    try {\n      datasource.close();\n    } catch(Exception e) {\n      throw new IllegalStateException(e);\n    }\n  }\n}\n\nDeferredFutureTask\u003cX\u003e task = new DeferredFutureTask(new DatabaseTask());\ndm.when(task).done(...)\n```\n\nYou may also pass the `CancellationHandler` as an additional argument, for example\n\n```Java\nfinal DataSource datasource = ...;\nclass DatabaseTask extends Runnable {\n  @Override\n  public void run() {\n    // perform computation with datasource\n  }\n}\n\nclass DatabaseCancellationHandler implements CancellationHandler {\n  @Override\n  public void onCancel() {\n    try {\n      datasource.close();\n    } catch(Exception e) {\n      throw new IllegalStateException(e);\n    }\n  }\n}\n\nDeferredFutureTask\u003cX\u003e task = new DeferredFutureTask(new DatabaseTask(), new DatabaseCancellationHandler());\ndm.when(task).done(...)\n```\n\n\u003ca name=\"example-groovy\"\u003e\u003c/a\u003eGroovy\n-----\nYou can also easily use with Groovy!\n\n```Groovy\n@Grab('org.jdeferred.v2:jdeferred-core:2.0.0')\nimport org.jdeferred2.*\nimport org.jdeferred2.impl.*\n\ndef deferred = new DeferredObject()\ndef promise = deferred.promise()\n\npromise.done { result -\u003e\n  println \"done: $result\" \n}.fail { rejection -\u003e\n  println \"fail: $rejection\"\n}.always { state, result, rejection -\u003e\n  println \"always\"\n}\n\ndeferred.resolve(\"done\")\n```\n\n\u003ca name=\"example-android\"\u003e\u003c/a\u003eAndroid Support\n---------------\n\u003e Since 1.1.0-Beta1\n\n```jdeferred-android``` is now available, and it can be included just like any other Android libraries!\nIt also uses Android Maven plugin and builds apklib file.  If you use Android Maven plugin, you can include\ndependency:\n\nAPKLIB with Maven:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.jdeferred.v2\u003c/groupId\u003e\n  \u003cartifactId\u003ejdeferred-android\u003c/artifactId\u003e\n  \u003cversion\u003e${version}\u003c/version\u003e\n  \u003ctype\u003eapklib\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\n\nAAR with Maven:\n\u003e Since 1.2.0-Beta1\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.jdeferred.v2\u003c/groupId\u003e\n  \u003cartifactId\u003ejdeferred-android-aar\u003c/artifactId\u003e\n  \u003cversion\u003e${version}\u003c/version\u003e\n  \u003ctype\u003eaar\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\nAAR with Gradle:\n```\ncompile 'org.jdeferred.v2:jdeferred-android-aar:${version}'\n// or\ncompile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'\n```\n\nFind available versions on [Maven Central Repository](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.jdeferred.v2%22%20AND%20a%3A%22jdeferred-core%22).\n\n```jdeferred-android``` introduces a new ```DeferredManager``` implementation called ```AndroidDeferredManager```.\n```AndroidDeferredManager``` makes sure that callbacks are executed in UI Thread rather than background Thread\nin order for callbacks to make UI updates.  Alternatively, callbacks can also implement ```AndroidExecutionScopeable```\ninterface to fine-grain control whether the callback should execute in UI Thread or background Thread.\n\n```AndroidDeferredManager``` also supports new ```DeferredAsyncTask``` object.  This object is based on \nAndroid's ```AsyncTask```.\n\nIf you need to always execute callbacks in background thread, then you can continue to use ```DefaultDeferredManager```.\n\nLastly, because JDeferred use SLF4J - you can further route log messages using ```slf4j-android```.\n\n\n\u003ca name=\"example-async-servlet\"\u003e\u003c/a\u003eAsynchronous Servlet\n--------------------\nHere is a sample code on how to use JDeferred with Asynchronous Servlet!\n\n```java\n@WebServlet(value = \"/AsyncServlet\", asyncSupported = true)\npublic class AsyncServlet extends HttpServlet {\n  private static final long serialVersionUID = 1L;\n  private ExecutorService executorService = Executors.newCachedThreadPool();\n  private DeferredManager dm = new DefaultDeferredManager(executorService);\n\n  protected void doGet(HttpServletRequest request,\n                       HttpServletResponse response) throws ServletException, IOException {\n    final AsyncContext actx = request.startAsync(request, response);\n    \n    dm.when(new Callable\u003cString\u003e() {\n      @Override\n      public String call() throws Exception {\n        if (actx.getRequest().getParameter(\"fail\") != null) {\n          throw new Exception(\"oops!\");\n        }\n        Thread.sleep(2000);\n        return \"Hello World!\";\n      }\n    }).then(new DoneCallback\u003cString\u003e() {\n      @Override\n      public void onDone(String result) {\n        actx.getRequest().setAttribute(\"message\", result);\n        actx.dispatch(\"/hello.jsp\");\n      }\n    }).fail(new FailCallback\u003cThrowable\u003e() {\n      @Override\n      public void onFail(Throwable exception) {\n        actx.getRequest().setAttribute(\"exception\", exception);\n        actx.dispatch(\"/error.jsp\");\n      }\n    });\n  }\n}\n```\n\u003c!-- Google Code for GitHub Visit Conversion Page --\u003e\n\u003cscript type=\"text/javascript\"\u003e\n/* \u003c![CDATA[ */\nvar google_conversion_id = 974052972;\nvar google_conversion_language = \"en\";\nvar google_conversion_format = \"3\";\nvar google_conversion_color = \"ffffff\";\nvar google_conversion_label = \"wsVZCOycvgkQ7Ly70AM\";\nvar google_conversion_value = 0;\nvar google_remarketing_only = false;\n/* ]]\u003e */\n\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"//www.googleadservices.com/pagead/conversion.js\"\u003e\n\u003c/script\u003e\n\u003cnoscript\u003e\n\u003cdiv style=\"display:inline;\"\u003e\n\u003cimg height=\"1\" width=\"1\" style=\"border-style:none;\" alt=\"\" src=\"//www.googleadservices.com/pagead/conversion/974052972/?value=0\u0026amp;label=wsVZCOycvgkQ7Ly70AM\u0026amp;guid=ON\u0026amp;script=0\"/\u003e\n\u003c/div\u003e\n\u003c/noscript\u003e\n\n\u003ca name=\"deprecations\"\u003e\u003c/a\u003eDeprecations\n==============\n\n\u003ca name=\"deprecations-v1.2.5\"\u003e\u003c/a\u003ev1.2.5\n--------\n* ~~```DeferredManager.StartPolicy.MANAUL```~~ is deprecated and will be removed in the next minor version. Use ```DeferredManager.StartPolicy.MANUAL``` instead.\n","funding_links":[],"categories":["Uncategorized","并发编程"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdeferred%2Fjdeferred","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdeferred%2Fjdeferred","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdeferred%2Fjdeferred/lists"}