@ 260528.1

231103.1 · 7f4a9ed91bbecb84e39f4bc8030247ce5116ddf8

Reorganize examples into categorized folders (#341)

* refactor: create directory structure to organize exmaples
* test: update test_all to work with new directory structure
* fix: bug in test_all if no package.json scripts
* test: cleanup output of test_all
* fix: remove default test script that throws from thread_safe_function_with_object_wrap
* fix: remove build_with_cmake from .gitignore
* fix: swith to ' from " and remove subdir from getAllTests call
* test: add extra test cases for npm start and just running the pkgJson.main with node
* refactor: move all examples to src directory
* refactor: add numbers to categories so they are ordered in the src folder
* refactor: simplify getAllExamples in test_all.js
* docs: add directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure example in readme
* add back build_with_cmake --------- Co-authored-by: legendecas <legendecas@gmail.com>

reading declarations

Changes to src/5-async-work/async_work_promise/napi/. All files

src/5-async-work/async_work_promise/napi/binding.c

new file mode 100644@@ -0,0 +1,170 @@+#include <stdio.h>+#include <stdlib.h>+#include <node_api.h>++// Limit ourselves to this many primes, starting at 2+#define PRIME_COUNT 10+#define CHECK(expr) \+  { \+    if ((expr) == 0) { \+      fprintf(stderr, "%s:%d: failed assertion `%s'\n", __FILE__, __LINE__, #expr); \+      fflush(stderr); \+      abort(); \+    } \+  }++typedef struct linked_box_s linked_box_t;+struct linked_box_s {+  linked_box_t* prev;+  int the_prime;+};++typedef struct {+  napi_async_work work;+  napi_deferred deferred;+  int data[PRIME_COUNT];+} AddonData;++// This function runs on a worker thread. It has no access to the JavaScript.+static void ExecuteWork(napi_env env, void* data) {+  AddonData* addon_data = (AddonData*)data;+  int idx_inner, idx_outer;+  int prime_count = 0;++  // Find the first 1000 prime numbers using an extremely inefficient algorithm.+  for (idx_outer = 2; prime_count < PRIME_COUNT; idx_outer++) {+    for (idx_inner = 2; idx_inner < idx_outer; idx_inner++) {+      if (idx_outer % idx_inner == 0) {+        break;+      }+    }+    if (idx_inner < idx_outer) {+      continue;+    }++    // Save the prime number to the heap. The JavaScript marshaller (CallJs)+    // will free this item after having sent it to JavaScript.+    addon_data->data[prime_count] = idx_outer;+    ++prime_count;+  }+}++// This function runs on the main thread after `ExecuteWork` exits.+static void WorkComplete(napi_env env, napi_status status, void* data) {+  if (status != napi_ok) {+    return;+  }++  AddonData* addon_data = (AddonData*)data;+  napi_value array;+  CHECK(napi_create_array(env, &array) == napi_ok);++  for (uint32_t idx = 0; idx < PRIME_COUNT; idx++) {+    napi_value js_the_prime;++    // Convert the integer to a napi_value.+    CHECK(napi_create_int32(env, addon_data->data[idx], &js_the_prime) == napi_ok);++    // Store the js value in the array.+    CHECK(napi_set_element(env, array, idx, js_the_prime) == napi_ok);+  }+  CHECK(napi_resolve_deferred(env, addon_data->deferred, array) == napi_ok);++  // Clean up the work item associated with this run.+  CHECK(napi_delete_async_work(env, addon_data->work) == napi_ok);++  // Set both values to NULL so JavaScript can order a new run of the thread.+  addon_data->work = NULL;+  addon_data->deferred = NULL;+}++// Create a deferred promise and an async queue work item.+static napi_value StartWork(napi_env env, napi_callback_info info) {+  napi_value work_name, promise;+  AddonData* addon_data;++  // Retrieve the per-addon data.+  CHECK(napi_get_cb_info(env,+                          info,+                          NULL,+                          NULL,+                          NULL,+                          (void**)(&addon_data)) == napi_ok);++  // Ensure that no work is currently in progress.+  CHECK(addon_data->work == NULL && "Only one work item must exist at a time");++  // Create a string to describe this asynchronous operation.+  CHECK(napi_create_string_utf8(env,+                                 "Node-API Deferred Promise from Async Work Item",+                                 NAPI_AUTO_LENGTH,+                                 &work_name) == napi_ok);++  // Create a deferred promise which we will resolve at the completion of the work.+  CHECK(napi_create_promise(env,+                             &(addon_data->deferred),+                             &promise) == napi_ok);++  // Create an async work item, passing in the addon data, which will give the+  // worker thread access to the above-created deferred promise.+  CHECK(napi_create_async_work(env,+                                NULL,+                                work_name,+                                ExecuteWork,+                                WorkComplete,+                                addon_data,+                                &(addon_data->work)) == napi_ok);++  // Queue the work item for execution.+  CHECK(napi_queue_async_work(env, addon_data->work) == napi_ok);++  // This causes created `promise` to be returned to JavaScript.+  return promise;+}++// Free the per-addon-instance data.+static void addon_getting_unloaded(napi_env env, void* data, void* hint) {+  AddonData* addon_data = (AddonData*)data;+  CHECK(addon_data->work == NULL &&+      "No work item in progress at module unload");+  free(addon_data);+}++// The commented-out return type and the commented out formal function+// parameters below help us keep in mind the signature of the addon+// initialization function. We write the body as though the return value were as+// commented below and as though there were parameters passed in as commented+// below.+/*napi_value*/ NAPI_MODULE_INIT(/*napi_env env, napi_value exports*/) {++  // Define addon-level data associated with this instance of the addon.+  AddonData* addon_data = (AddonData*)malloc(sizeof(*addon_data));+  addon_data->work = NULL;++  // Define the properties that will be set on exports.+  napi_property_descriptor start_work = {+    "startWork",+    NULL,+    StartWork,+    NULL,+    NULL,+    NULL,+    napi_default,+    addon_data+  };++  // Decorate exports with the above-defined properties.+  CHECK(napi_define_properties(env, exports, 1, &start_work) == napi_ok);++  // Associate the addon data with the exports object, to make sure that when+  // the addon gets unloaded our data gets freed.+  CHECK(napi_wrap(env,+                   exports,+                   addon_data,+                   addon_getting_unloaded,+                   NULL,+                   NULL) == napi_ok);++  // Return the decorated exports object.+  return exports;+}

src/5-async-work/async_work_promise/napi/binding.gyp

new file mode 100644@@ -0,0 +1,8 @@+{+  'targets': [+    {+      'target_name': 'binding',+      'sources': [ 'binding.c' ]+    }+  ]+}

src/5-async-work/async_work_promise/napi/index.js

new file mode 100644@@ -0,0 +1,10 @@+// Use the "bindings" package to locate the native bindings.+const binding = require('bindings')('binding');++// Call the function "startWork" which the native bindings library exposes.+// The function returns a promise which will be resolved at the complete of the+// work with an array of worked out primes. This resolution simply prints them out.+binding.startWork()+  .then((thePrimes) => {+    console.log("Received primes from completed work: " + thePrimes)+  });

src/5-async-work/async_work_promise/napi/package.json

new file mode 100644@@ -0,0 +1,17 @@+{+  "name": "async_work_promise",+  "version": "0.0.0",+  "description": "Calling into JS from the thread pool",+  "main": "index.js",+  "private": true,+  "dependencies": {+    "bindings": "~1.5.0"+  },+  "engines": {+    "node": ">= 10.6.0"+  },+  "scripts": {+    "test": "node index.js"+  },+  "gypfile": true+}